mysql小知识
Contents
事务的基本要素
- 原子性 事务开始后的所有操作要么做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错会回滚到事务开始的状态。所有的操作就像没有发生过一样。也就是说一个事务是一个不可分割的整体。(undo log实现)
-
一致性 事务开始前和结束后,数据库的完整约束没有被破坏。如A向B赚钱,不可能A扣了钱,B却没收到。
-
隔离性 统一时间只允许一个事务请求同一数据,不同事务之间彼此没有任何干扰。比如A正从银行开中取钱,在A取钱的过程中,B不能向这张卡转账。
-
持久性 事务一旦提交,其更改是永久性的,即使数据库系统崩溃也能恢复。(redo log实现)
redo log也是需要在事物提交时将日志写入硬盘,为什么它比直接将Buffer Pool中修改的数据写入硬盘(脏刷)要快?
- 脏刷是随机IO,因为每次修改的数据位置随机,但写redo log是追加操作,属于顺序IO
- 脏刷以数据页(Page)为单位,mysql默认页大小为16KB,一个Page上一个小修改都要整页写入;而redo log只包含真正需要写入的部分,无效IO大大减少
redo log与binlog
binlog(二进制日志)也可以用于记录操作并用于数据的恢复,其和redo log的区别如下
- 作用不同 redo log用于crash recovery,保证mysql宕机也不会影响持久性,而binlog用于point-in-time recovery,保证服务器可以基于时间点恢复数据,另外binlog还用于主从复制
- 层次不同 redo log是InnoDB存储引擎实现的,而binlog是mysql服务器层实现的
- 内容不同 redo log是物理日志,内容基于硬盘page;binlog的内容是二进制的,根据binlog_format参数不同,可能基于sql语句、基于数据本身或者二者的混合
- 写入时机不同 binlog在事物提交时写入;redo log的写入时机相当多元(可以根本配置策略不同改变写入时机)
不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
Mysql创建索引需要遵守原则
-
选择唯一性索引
值是唯一的,例如学生表中的学号
-
为经常需要排序、分组和联合操作的字段建立索引
经常需要order by、group by、distinct和union等操作的字段,排序操作费时。建立索引影后可以有效避免排序操作
-
为经常作为查询条件的字段建立索引
作为查询条件,为这样的字段建立索引可以提供整张表的查询速度
-
限制索引的数目
索引的数目不是越多越好,每个索引都占用硬盘空间,索引越多,需要的空间就越大。需改表时,对索引的重构和更新很麻烦。索引越多,更新表越费时
-
尽量使用数据少的索引
如果索引的值很长,那么查询的速度会受到影响
-
尽量使用前缀来索引
如果索引字段的值很长,最好使用值的前缀来索引
-
删除不再使用或很少使用的索引
-
最左匹配原则
Mysql会一直向右匹配,知道遇到范围查询(<、>、between、like)就停止匹配。如a = 1 and b = 2 and c > 3 and d = 4,如果建立(a,b,c,d)顺序的索引,d是用不到索引的,如果建立(a,b,d,c)顺序的索引,则都可以用到,且a,b,d顺序可以任意调整。
-
=和in可以乱序
比如a = 1 and b = 2 and c = 3,建立(a,b,c)索引,a,b,c可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式。
-
尽量选择区分度高的列作为索引
区分度计算公式: count(distinct(col))/count(*),表示字段不重复的比例,比例越大,扫描的记录数据越少。
-
索引不能参与计算,保持“列干净”
比如from_unixtime (create_time) = ‘2020-07-08’ 就不能用到索引,因为B+树中存的是数据表中的字段值,但是进行检索时,需要把所有元素都应用函数才能比较,成本太大。语句应该写成create_time = unix_timestamp(‘2020-07-08’)
-
尽量的扩展索引,不要新建索引
Author 聪少
LastMod 2020-07-20