MySQL中一些概念
1.当前读
当前事务对某行数据更新,先读再写,读时可能获得其他事务更新后的数据,这里必须获得因为数据库要保证更新不丢失,这里就违背了rr隔离级别的一致性视图,该现象为当前读现象。
类似的,当前事务使用select进行加锁读的时候,无论share mode还是for update,都可能和其他事务的写锁冲突,因此也会触发当前读。
当前读和锁等待密不可分。
2.online ddl
用delete不能释放表占用空间,mysql只将记录或者数据页标记为可删除,便于之后的复用,只是逻辑删除了数据,没有释放物理存储。
使用alter语句重建表就可以去除空洞,缩小表占用空间,即ddl过程。为了实现online,需要两点:
对原来表仍然可以进行DML,这些操作记录先记录在log中,重建表全部拷贝完成后,将log重放到tmp表中。
开始获取MDL写锁,短暂保持直到完成记录表结构(row log)等关键性操作,然后降级为MDL读锁,可以做dml操作。
3.不走索引的情况
where中有函数,优化器担心破坏了索引的有序性,因此走全表扫描;另外隐式类型转换和隐式字符编码转换也相当于有函数。mysql中将字符串转整形;有时联表查询不同表字符编码不一样,用不上索引。
4.查询卡住需要检查的几种情况
卡住:可能是在等MDL释放写锁或者释放请求写锁;可能是在等待flush表;可能是在等待行锁。
查询很慢:可能是走的全表扫描,数据量大;可能是回滚段很长,如果使用select share mode,触发当前读,速度很快。
5.幻读
发生在rr隔离级别,一个事务前后查询相同范围的数据,后一次读到了不存在的行。在普通快照读没有,在当前读情况才能发现幻读。幻读专门指插入新的数据。
幻读带来的数据不一致:在日志和逻辑上的不一致,多个事务并发过程锁能保证数据的正确性,而bin log日志是在每个事务即将提交之前写的,可能导致对各事务中各语句记录乱序,在恢复或者备份的时候导致数据的不一致。
加间隙锁,能锁住意向值左右的间隙,防止插入;也能锁住扫描到的行,由于innodb引擎会扫描到不存在的行为止,也就锁住了表中不存在的意向值能插入的间隙。
rr级别下为了解决幻读,引入的间隙锁,影响并发度,例如两个事务同时想插入一行数据,都先上了间隙锁,然后插入死锁。相对而言另一种解决思路是:使用读提交隔离级别,外加row格式的日志解决日志不一致的问题。
间隙锁的一些加锁原则:加锁的基本单位是next-key lock,是前开后闭的;对扫描到的行才会加锁;等值查询碰到唯一索引退化为行锁;等值查询遍历到最后一个不满足条件的退化为间隙锁;(一个bug),唯一索引也会扫描到不满足的一个为止。
间隙锁如果是覆盖索引,在share mode模式,不会锁住主键索引,对主键索引的更新还是可以的,在for update模式,会对主键索引上满足条件的行加锁。
6.慢查询
索引没有设计好:通过alter table实现online ddl解决,可以备库关闭bin log先做ddl,然后主备切换。
sql语句没有写好:可以rewrite
索引选错了:紧急使用force index
7.主备延迟
延迟时间:主库写入binlog日志到备库执行完拷贝过来的binlog日志之间的时间。
造成的问题:拖慢relay log的消费速度,导致其比主库产生bin log速度慢,形成恶循环。
物理上处理跟不上的原因:备库cpu资源差了,可能被用于大量查询场景,可以用多从库解决方案。
其他原因:主库上出现了长事务,很久才更新到bin log。可能备库的并行复制能力较差。
可能备库的并行复制能力较差,形成恶循环,延迟会越来越大:
解决办法:备库并发执行sql thread,将relay log中的内容重放到备库中。使用多个worker线程,主线程只负责分发,worker线程实际处理问题。需要注意:同一行的多个更新要用一个worker处理;同一事务不能拆开,要使用一个worker处理。
长事务可能有DML和DDL,例如大量的delete操作,例如对大表的DDL。
主备切换策略分两类:可靠性优先,可用性优先。
可靠性优先:主库不产生新的bin log,硬等到和备库之间的延迟时间为0,才做主备切换。
可用性优先:备库直接上线,这样可能新的用户请求排在了bin log的同步之前,导致主备不一致,使用row格式的bin log产生主键id错误的时候会报错,因此主备不一致的情况更容易被发现。
主备切换的时候,第一阶段change master时候需要找到bin log同步的位置,GTID:全局事务id,事务的唯一标志,格式为server_uuid:gno,gno初始为1,每次提交时候给这个事务,并+1,gno和事务id不同,它提交的时候才会分配,而事务id回滚之后也会递增。
读写分离,一主多从模式:业务场景中往往读多些少,将读请求分担到多个从库上。带来的问题:主库更新了,从库没来及,在从库上读到的数据过期了,称为过期读。
过期读的解决办法:
强制走主库:需要拿到最新数据的请求,走主库,能接受延迟的,走从库,可能读到旧数据。
从库sleep一下:不接受客户端请求,后台同步,等到主备延迟降为0,此期间前端可以假装返回了完成之后的页面。
判断主从无延迟:判断主从延迟=0再查询。对比位点或者GTID保证无延迟即可,比seconds_behind_master=0更准确。
semi-sync:解决的问题:主库事务完成了,返回给客户端,从库此时还没有完成,客户端在从库过期读。办法:主库完成后发给从库binlog,从库完成后回复主库ack,主库回复客户端事务commit。带来的新问题:一主多从不能命中目标从库。
8.并发连接和并发线程
连接占用内存;并发线程在mysql中实际是并发活跃线程,占用cpu。

浙公网安备 33010602011771号