事务的基本要素

  • 原子性 事务开始后的所有操作要么做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错会回滚到事务开始的状态。所有的操作就像没有发生过一样。也就是说一个事务是一个不可分割的整体。(undo log实现)
  • 一致性 事务开始前和结束后,数据库的完整约束没有被破坏。如A向B赚钱,不可能A扣了钱,B却没收到。

  • 隔离性 统一时间只允许一个事务请求同一数据,不同事务之间彼此没有任何干扰。比如A正从银行开中取钱,在A取钱的过程中,B不能向这张卡转账。

  • 持久性 事务一旦提交,其更改是永久性的,即使数据库系统崩溃也能恢复。(redo log实现)

redo log也是需要在事物提交时将日志写入硬盘,为什么它比直接将Buffer Pool中修改的数据写入硬盘(脏刷)要快?

  1. 脏刷是随机IO,因为每次修改的数据位置随机,但写redo log是追加操作,属于顺序IO
  2. 脏刷以数据页(Page)为单位,mysql默认页大小为16KB,一个Page上一个小修改都要整页写入;而redo log只包含真正需要写入的部分,无效IO大大减少

redo log与binlog

binlog(二进制日志)也可以用于记录操作并用于数据的恢复,其和redo log的区别如下
  1. 作用不同 redo log用于crash recovery,保证mysql宕机也不会影响持久性,而binlog用于point-in-time recovery,保证服务器可以基于时间点恢复数据,另外binlog还用于主从复制
  2. 层次不同 redo log是InnoDB存储引擎实现的,而binlog是mysql服务器层实现的
  3. 内容不同 redo log是物理日志,内容基于硬盘page;binlog的内容是二进制的,根据binlog_format参数不同,可能基于sql语句、基于数据本身或者二者的混合
  4. 写入时机不同 binlog在事物提交时写入;redo log的写入时机相当多元(可以根本配置策略不同改变写入时机)

不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表

Mysql创建索引需要遵守原则

  1. 选择唯一性索引

    值是唯一的,例如学生表中的学号

  2. 为经常需要排序、分组和联合操作的字段建立索引

    经常需要order by、group by、distinct和union等操作的字段,排序操作费时。建立索引影后可以有效避免排序操作

  3. 为经常作为查询条件的字段建立索引

    作为查询条件,为这样的字段建立索引可以提供整张表的查询速度

  4. 限制索引的数目

    索引的数目不是越多越好,每个索引都占用硬盘空间,索引越多,需要的空间就越大。需改表时,对索引的重构和更新很麻烦。索引越多,更新表越费时

  5. 尽量使用数据少的索引

    如果索引的值很长,那么查询的速度会受到影响

  6. 尽量使用前缀来索引

    如果索引字段的值很长,最好使用值的前缀来索引

  7. 删除不再使用或很少使用的索引

  8. 最左匹配原则

    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顺序可以任意调整。

  9. =和in可以乱序

    比如a = 1 and b = 2 and c = 3,建立(a,b,c)索引,a,b,c可以任意顺序,mysql的查询优化器会帮你优化成索引可以识别的形式。

  10. 尽量选择区分度高的列作为索引

    区分度计算公式: count(distinct(col))/count(*),表示字段不重复的比例,比例越大,扫描的记录数据越少。

  11. 索引不能参与计算,保持“列干净”

    比如from_unixtime (create_time) = ‘2020-07-08’ 就不能用到索引,因为B+树中存的是数据表中的字段值,但是进行检索时,需要把所有元素都应用函数才能比较,成本太大。语句应该写成create_time = unix_timestamp(‘2020-07-08’)

  12. 尽量的扩展索引,不要新建索引