MySql索引原理及优化

455 阅读3分钟

索引

目的:提高查询效率,

原理本质:通过不断的缩小想要获得数据的范围来筛选出最终需要的结果,就像查字典一样,比如查找hello,我们必定是先找到h开头的单词,再找he开头的单词…

磁盘IO和预读

磁盘读取数据依靠的是机械运动,每次读取数据花费的时间可以分为寻道时间,旋转时间,传输时间

  • 寻道时间:磁臂移动到指定磁道所需要的时间,一般在5ms以下
  • 旋转延迟:我们经常说的磁盘转速,比如一个磁盘7200转(表示一分钟可以转7200次,旋转延迟就是1/120/2=4.17ms)
  • 传输时间: 从磁盘(读出/写入)磁盘的时间,一般是零点几毫秒

因为磁盘IO是非常高昂的操作,操作系统做了一些优化,会将相邻的数据也都读取到内存缓冲区中

注意📢:访问磁盘的成本大概是访问内存的十万倍左右

索引的数据结构

索引是为了提高查询效率,而数据是存储在硬盘中,所以我们需要提高磁盘查询的速度

又因为访问磁盘的成本太高,所以我们需要有一个数据结构能够满足下列要求:

  • 每次查找数据时把磁盘IO次数控制在一个很小的数量级,最好是常数数量级

在一般场景中,我们如果要查询有顺序的数据,我们会使用二叉树,而二叉树因为高度不可控,IO次数取决于树高度,如果树的高度太高会导致产生较多次的磁盘IO。所以我们不能选择二叉树

然后,前辈们就发明了B+树,一颗高度可控的多路搜索树

Untitled.png

假设当前数据表的数据为N,每个磁盘块的数据项的数量是m,则树高度h = log(m+1)N

磁盘块的大小也就是一个数据页的大小,是固定的,如果数据项的空间越小,数据项的数量越多,也就是m越大,h就会越小。即索引字段越小,树高度越小。

所以要求把真实的数据放到叶子节点而不是内层节点

查询优化

  • 最左前缀匹配原则:mysql会一直向右匹配直到遇到范围查询(>, <, between, like)

    比如 a = 1 and b = 2 and c > 3 and d = 4

    • 如果建立(a,b,c,d)顺序的索引,d是用不到索引的
    • 如果建立(a,b,d,c)的索引,则都可以用到
  • 选择区分度高的列作为索引(字段不重复的比例越高越好,比如主键Id的字段区分度就是1,因为主键唯一,不可能出现重复)

  • 尽量扩展索引,而不是新建索引(因为索引的维护是需要开销的,数据量越多,所花费的时间和算力就不断递增)

    比如:已经有了一个(a)的索引,现在要增加(a,b)的索引,则只需要将(a)索引修改为(a,b)索引

explain命令

我们可以使用explain命令来查看sql语句的执行计划,查看该sql语句有没有使用上索引,有没有做全表扫描,这个在数据库优化中,是一个非常强力的工具

下图是mysql中explain命令的输出结果中的字段解释

Untitled 1.png

其中rows是核心指标,绝大部分rows小的语句执行一定很快。所以优化基本上都是在优化rows

参考资料

tech.meituan.com/2014/06/30/…

dev.mysql.com/doc/refman/…

www.cnblogs.com/xuanzhi2011…

www.cnblogs.com/duanxz/arch…