mysql基本知识点

mysql

1) 存储引擎

a) myisam
不支持事务, 访问速度快
R/W > 100 : 1并且Update较少 (R/W:读写比)
并发不高,不需要支持事务
表数据量小, 需要进行全文搜索
b) innodb
支持事务
自动增长列auto_increment
R/W比较小,频繁更新大字段
表数据量超过千万,高并发
c) memory(数据存内存),merge(一组myisam表)

2)

a) 表级锁: myisam和innodb都有;加锁快开销小,不会死锁,锁冲突高并发度低
不阻塞读请求,阻塞写请求;读读可以并行,读写和写写是串行的
不会产生死锁,因为一次性获得了所有锁,其它请求此时处于阻塞状态
执行select语句时自动加读锁,执行delete,update,insert语句自动加写锁
InnoDB引擎只有通过索引条件检索数据,才使用行级锁,否则,InnoDB将使用表锁
b) 行锁:innodb才有;开销大加锁慢,会死锁,锁冲突低并发高
共享锁(Share lock,读锁): SELECT ... LOCK IN SHARE MODE
i. 在查询语句后面增加LOCK IN SHARE MODE,Mysql会对查询结果中的每行都加共享锁
ii. 当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请共享锁,否则会被阻塞
iii. 其他线程也可以读取使用了共享锁的表,而且这些线程读取的是同一个版本的数据
iv. 任何事务都不能对数据进行修改(获取数据上的排他锁),直到已释放所有共享锁
排他锁(eXclusive Lock,写锁): SELECT ... FOR UPDATE
i. 在查询语句后面增加FOR UPDATE,Mysql会对查询结果中的每行都加排他锁
ii. 当没有其他线程对查询结果集中的任何一行使用排他锁时,可以成功申请排他锁,否则会被阻塞
c) 死锁: 一般是事务相互等待对方资源,最后形成环路造成的
不同表相同记录行锁冲突: 事务A和事务B操作两张表,但出现循环等待锁情况

相同表记录行锁冲突: 两个job在执行数据批量更新时,jobA处理的的id列表为[1,2,3,4],而job处理的id列表为[8,9,10,4,2],就造成了死锁

gap锁冲突: innodb在RR(repeatable read,可重复读)级别下,如下的情况也会产生死锁

避免死锁
i. 以固定的顺序访问表和行。如例2两个job批量更新的情形,可对id列表先排序,后执行,这样就避免了交叉等待锁的情形;又比如对于例1,将两个事务的sql顺序调整为一致
ii. 大事务拆小。大事务更倾向于死锁,如果业务允许,将大事务拆小
iii. 在同一个事务中,尽可能做到一次锁定所需要的所有资源,减少死锁概率
iv. 降低隔离级别。如果业务允许,将隔离级别调低也是较好的选择,比如将隔离级别从RR调整为RC,可以避免掉很多因为gap锁造成的死锁
v. 为表添加合理的索引。如果不走索引将会为表的每一行记录添加上锁,死锁的概率大大增大
d) 悲观锁: 即innodb的行级排他锁
e) 乐观锁: 
一般的实现乐观锁的方式就是记录数据版本version
读取数据时,将版本标识的值一同读出,数据每更新一次,同时对版本标识进行更新
提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的版本标识进行比对
如果数据库表当前版本号与第一次取出来的版本标识值相等,则予以更新,否则认为是过期数据
使用版本号时,可以在数据初始化时指定一个版本号,每次对数据的更新操作都对版本号执行+1操作

3) 事务

a) 是指作为单个逻辑工作单元执行的一系列操作,要么完全执行,要么完全地不执行
b) ACID
Atomicity原子性:一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节
Consistency一致性:使数据库从一个一致的状态变到另外一个一致的状态
i. 在事务T开始时,此时数据库有一种状态, 如数据库完整性约束正确,日志状态一致等
ii. 当事务T提交后,这时数据库又有了一个新的状态,不同的数据,不同的索引,不同的日志等
iii. 但此时,约束,数据,索引,日志等MySQL各种对象还是要保持一致性(正确性)
iv. 从一个一致性的状态,变到另一个一致性的状态
Isolation隔离性: 指当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离; 对于任意两个并发的事务T1和T2,在事务T1看来,T2要么在T1开始之前就已经结束,要么在T1结束之后才开始,这样每个事务都感觉不到有其他事务在并发地执行
Durability 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失
c) 三种读现象
脏读
i. 当一个事务A正在访问数据,并且对数据进行了修改,而这种修改还没有提交到数据库中
ii. 另外一个事务B同时访问这个数据,且得到了修改后的数据
iii. 此时事务A回滚了, 事务B得到的数据是不正确的, 是脏数据
不可重复读
i. 在一个事务A内,多次读同一数据
ii. 在这个事务A还没有结束时,另外一个事务B也访问并修改了同一数据
iii. 在B执行完之前读到的数据跟在B执行完之后读到的数据不一致
iv. 在事务A重复读同一数据结果不一致, 即没法重复读, 不可重复读
幻读
i. 第一个事务对一个表中的数据进行了修改,这种修改涉及到表中的全部数据行
ii. 同时,第二个事务也修改这个表中的数据,这种修改是向表中插入一行新数据
iii. 那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一样
d) 四种事务隔离级别
未提交读(Read uncommitted): 可能会出现脏读,不可重复读,幻读
已提交读(Read committed): 可能出现不可重复读,幻读
可重复读(Repeatable read): 可能出现幻读
串行化(Serializable): 不会出现脏读,不可重复读,幻读; 完全串行化,每次读都需要获得表级共享锁,读写相互都会阻塞

4) 分布式事务

a) 用来保障在分布式环境下事务的强一致性
b) 一致性理论
强一致性: 当更新操作完成之后,多个后续请求访问的都是最新的值;如,数据库事务
弱一致性: 当更新操作完成之后,不保证后续请求的访问都是最新的值
最终一致性: 弱一致性的特定形式,系统保证在没有后续更新的前提下,系统最终返回上一次更新操作的值
c) cap理论: 一个分布式系统最多只能同时满足一致性,可用性和分区容错性这三项中的两项
Consistency:强一致性就是在客户端任何时候看到各节点的数据都是一致的
Availability:高可用性就是在任何时候都可以读写
Partition Tolerance:分区容错性是在网络故障、某些节点不能通信的时候系统仍能继续工作,分区相当于对通信的时限要求,系统如果不能在时限内达成数据一致性,必须就当前操作在C和A之间做出选择,要么cp,要么ap
d) base理论: 系统基本可用,不要去一直保持强一致性状态,但需要在某一个时刻后达到一致性状态
e) 二阶段提交
第一阶段: 投票阶段
i. 协调者向所有的参与者发送事务执行请求,并等待参与者反馈事务执行结果
ii. 事务参与者收到请求之后,执行事务,但不提交,并记录事务日志
iii. 参与者将自己事务执行情况反馈给协调者,同时阻塞等待协调者的后续指令
第二阶段:事务提交阶段
i. 如果所有的参与者回复能够正常执行事务
ii. 协调者向各个参与者发送commit通知,请求提交事务
iii. 参与者收到事务提交通知之后,执行commit操作,然后释放占有的资源
iv. 参与者向协调者返回事务commit结果信息
f) 三阶段提交: 相比二阶段提交, 引入一个“预询盘”阶段,以及超时策略来减少整个集群的阻塞时间
g) 分布式事务的实现方式
本地事务+消息表+消息队列
i. 本地事务执行完成(事务+消息表中插入一条消息记录)
ii. 通过轮询方式向MQ发送消息,保证发送成功
iii. 第三方接收消息处理事务
支持事务的中间件: rocketMQ
补偿机制: 定时任务轮询中间表数据
二阶段/三阶段提交

5) sql优化

a) 通过explain分析sql
b) 慢查询日志分析
c) 优化
in 使用 exist代替 
like中,通配符%只出现在右边,会走索引
如果只要一条数据,使用limit 1
为搜索字段建立索引
不用order by rand(),性能很差
避免selec *

6) 索引

a) 使用索引的场景: 匹配全值/匹配值的范围(a>10 and a<20)/匹配最左前缀(联合索引: 存在c1+c2+c3联合索引,只要where条件中出现c1的就会使用索引)
b) 存在但不使用的场景:like前面使用通配符/数据隐式类型转换/联合索引不满足最左原则/使用索引比全表扫更慢/是函数或表达式一部分/or条件只有一个字段创建索引
c) 适合创建索引的列: 作为条件的字段/作为排序的/经常被查询的

7) 集群方案

a) mycat,通过代理的方式, 核心功能是分表分库,可统一管理所有数据源

8) 主从

a) 通过binlog实现

9) 分库分表

a) 垂直拆分: 如果是库则将不同类型的表放同一个库/如果是表则按字段类型拆分
b) 水平拆分: 按单表数据量/按单表时间/按表中用户id
c) 全局id
snowflake,唯一但非全局递增, 推荐
mysql新建一张表用来生成全局唯一递增id(利用auto_increment功能), 大并发的情况下有性能问题
UUID: 包含字母, 不适合作为id
d) 联表查询sql改造: 业务上避免/冗余字段/代码中拼接
拆分后的数据一致性: 分布式事务解决
跨库join: 分多次查询
e) 路由策略
表: 假设10张表 则通过用户id对10取模找到对应的表 表序号=userId%10
库:
i. 中间变量 userId %(库数量 * 每个库中该表的数量)
ii. 库序号 取整(中间变量/每个库的表数量)
iii. 表序号 中间变量%每个库的表数量
中间件: mycat/sharding-jdbc/tddl

猜你喜欢

转载自blog.csdn.net/zyf_balance/article/details/78729336