MySQL 深入研究记录

提升查询速度,本质是减少磁盘IO次数

索引

索引是帮助MySQL搞笑获取数据的排好序数据结构

索引的数据结构

  • 二叉树(极端情况,会退化成链表,并不能减少查询次数)

  • 红黑树(二叉平衡树,会根据左右树高度进行平衡,但是数量越大,树的深度就越高,查询次数也会越来越高)

  • Hash表

  • B-Tree

  • B+

MySQL 底层采用B+ Tree 来存储索引

  • 非叶子节点不存在data,只存储索引(冗余),可以放更多的索引

  • 叶子节点包含所有索引字段

  • 叶子节点用指针连接,提高区间访问性能

图片.png
Figure 1. 图片.png
  • 叶子节点的数据按照顺序从左到右,数据依次由小到大。

  • 每个节点的大小约为16kb

  • 树的高度即为磁盘io次数,也即查找次数,通过b+树,树高度在3层,就支持2kw的数据。

InnoDB 和 MyISAM 存储引擎

形容数据库表结构

MyISAM 存储结构

  • table.frm 表结构

  • table.MYD 表数据

  • table.MYI 表索引

先走索引文件找到文件存储磁盘位置,然后在MYD文件中找到对应的记录。

InnoDB 存储结构

  • table.frm 表结构

  • table.ibd 索引加数据文件

聚集索引和非聚集索引的区别

聚集索引:将数据存储和索引放在一起,并且按照一定的顺序组织,找到索引也就找到了数据,数据的物理顺序和索引的顺序是一致的,只要索引是相邻的,那么对应的数据也一定是相邻的存放在磁盘上。 非聚集索引:索引和数据分开存储,索引只存储数据所在磁盘位置。根据索引找到数据行的位置,再通过回表查询磁盘所在的数据。

优势:

  1. 查询通过聚集索引可以直接获取数据,相比非聚集索引需要二次查询效率要高

  2. 聚集索引堆范围查询的效率很高,因为其数据是按照大小排列的

  3. 聚集索引适合用在排序的场合

劣势:

  1. 维护索引很昂贵,因为插入新行或主键更新导致树结构的分裂和平衡。

  2. 采用UUid作为主键,会出现聚集索引可能比全表扫描更慢

为什么InnoDB需要一个主键?并推荐使用整型的自增主键?

因为InnoDB表数据文件本身就是按B+树组织的一个索引结构文件,如果不使用主键,MySQL也会创建一个隐藏的主键。整型比较效率高于字符串,其二存储空间一般小于其他UUID。自增,当节点数据满了后,分裂平衡效率更高。

B+ 树 vs B树

  • 非叶子节点不存储数据,这样存储的索引数量更多,能存储更多的数据,得到的树层级更低

  • 叶子节点增减一个节点之间的双向连接。

联合索引

多个字段组合,按顺序进行排序。这里顺序是指多个字段组合起来的顺序,因此,必须符合最左匹配原则,如果用后面的字段是没有顺序的,无法走索引。

索引的设计原则

查询更快、占用空间更小

  1. 适合索引的列是出现在where子句中的列,或者连接子句中指定的列

  2. 基数较小的类,索引效果较差,没必要在此列建立索引

  3. 使用短索引,如果对长字符串列进行索引,应该指定一个前缀长度,节省索引空间

  4. 不要过度索引,索引需要额外的磁盘空间,并降低写操作,在修改表内容时,索引会更新甚至重构,索引列越多,时间越长,所以保持需要的索引即可

  5. 定义有外键的数据列一定要建立索引

  6. 更新频繁的字段不适合建立索引

  7. 区分度太低的列也不适合,也即列中可能的值很少,区域固定

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

  9. 查询少、重复值多的不要建立索引

  10. 对于text等大字段不要建立索引

基于锁的属性:共享锁、排他锁 基于锁的粒度: 行级锁,表级锁,页级锁,记录锁,间隙锁,临建锁 基于锁的状态分类:意向共享锁,意向排他锁

共享锁:

共享锁又称读锁,当一个事务对数据加上读锁后,其他事务只能对其数据加读锁,而不能对数据加写锁,知道所有的读锁释放后,其他事务才能加写锁。共享锁主要是为了支持并发读取数据,读取数据时不支持修改,避免出现重复读问题。

排他锁:

排他锁又称写锁,当一个事务为数据加上排他锁,其他事务不能为数据加任何锁,直到该锁释放。排他锁的目的是在数据修改时,不允许其他事务修改,也不允许其他事务读取,避免出现脏读或者脏数据问题。

表锁:

将整个表进行加锁 ,下一个事务必须等当前加锁的事务释放后才能进行访问

行锁:

锁住表的一行或多行,其他事务不能访问上锁的行,其他可以访问。特点:粒度小,加锁麻烦,不容易冲突,支持并发高

记录锁:

也属于行锁的一种,只是只能锁住一条数据,加了记录锁的数据后可以避免查询的时候被修改导致重复读问题,也避免了在修改事务未提交之前,其他事务脏读问题。

页锁:

粒度介于表锁和行锁之间,锁定相邻的一组记录。

explain