共计 1804 个字符,预计需要花费 5 分钟才能阅读完成。
通过一个例子看看索引的威力
t_user 表插入 1 百万条数据
查找 name = user0,耗时 213msselect * from t_user where name = 'user0'
减少 name 字段的索引ALTER TABLE t_user ADD INDEX index_name (
name)
再次查找,耗时 1ms
真厉害啊,但索引到底是个啥?为什么能够放慢数据库的检索速度呢?
首先说说 MySQL 默认引擎 InnoDB 的根本存储构造,Page(页)
* 数据是一条一条记录在页中的,组成一个单向链表。* 多个数据页能够组成一个双向链表。
页与记录的关系如下图:
再说说如果没有用索引,数据库是怎么查找记录的?
比方:SELECT [列名列表] FROM 表名 WHERE 列名 = xxx;
- 定位到记录所在的页。
-
从所在的页内中查找相应的记录,这里又分两种状况:
- 以主键为搜寻条件,在数据页中有对主键列建设页目录,通过主键查找某条记录的时候能够在页目录中应用二分法疾速定位到对应的槽,而后再遍历该槽对应分组中的记录即可疾速找到指定的记录。
- 以其余列为搜寻条件,在数据页中并没有对非主键列建设所谓的页目录,所以咱们无奈通过二分法疾速定位相应的槽。这种状况下只能从最小记录开始顺次遍历单链表中的每条记录,而后比照每条记录是不是合乎搜寻条件。很显然,这种查找的效率是非常低的。
不论是依据主键列或者其余列的值进行查找,因为咱们并不能疾速的定位到记录所在的页,所以只能从第一个页沿着双向链表始终往下找,在每一个页中依据咱们上边的查找形式去查找指定的记录。因为要遍历所有的数据页,所以这种形式显然是超级耗时的,如果一个表有一亿条记录,应用这种形式去查找记录那要等到猴年马月能力等到查找后果。
应用索引,放慢了查找速度的起因
不必索引查问慢的根本原因是不能疾速的定位到记录所在的页。
索引就是应用了 B + 树这种数据结构,将无序的数据变成了有序的数据,从而放慢了查找速度。
能够看到叶子节点存储的是数据记录页,非叶子节点存储是目录项记录页。
另外还有的特点:
- 页内的记录是依照列的大小程序排成一个单向链表。
- 各个寄存用户记录的页也是依据页中记录的列大小程序排成一个双向链表。
- 各个寄存目录项的页也是依据页中记录的列大小程序排成一个双向链表。
很显著的是:没有用索引 咱们是须要 遍历双向链表 来定位对应的页,当初通过 “目录” 就能够很快地定位到对应的页上了!
一些索引相干知识点
汇集和非汇集索引
- 汇集索引就是以 主键 创立的索引,汇集索引并不需要咱们在 MySQL 语句中显式的去创立,InnoDB 存储引擎会主动的为咱们创立汇集索引,叶子节点记录的是残缺的一条数据,即主键 + 所有列的一条数据
- 非汇集索引就是以 非主键 创立的索引,非汇集索引在叶子节点存储的是 主键和索引列 ,查问数据时,不能查找到残缺的一条数据, 必须再依据主键值去汇集索引生成的 B + 树中再查找一遍残缺的数据。拿到主键再查找这个过程叫做 回表 , 那为什么咱们还须要一次回表操作呢?间接把残缺的用户记录放到叶子节点不就好了么?因为把残缺的用户记录放到叶子节点是能够不必回表,然而太占中央了呀~相当于每建设一棵 B + 树都须要把所有的用户记录再都拷贝一遍,这就有点太节约存储空间了。
笼罩索引
下面的回表操作的起因是非汇集索引须要找到除了主键和索引列以外的字段数据,那么如果非汇集索引蕴含了满足查问语句中字段数据不就不须要回表了吗?就叫做笼罩索引。应用笼罩索引防止了回表的产生缩小了树的搜寻次数,显著晋升性能。
联结索引
即对多个列建设索引如 key index(a,b)。
即对于让 B + 树依照 a 和 b 列的大小进行排序,这个蕴含两层:
- 先把各个记录和页依照 a 列进行排序。
- 在记录的 a 列雷同的状况下,采纳 b 列进行排序
另外
- 建设联结索引只会建设 1 棵 B + 树。
- 为 a 和 b 列建设索引会别离以 a 和 b 列的大小为排序规定建设 2 棵 B + 树。
索引最左匹配准则
例如索引是 key index(a,b,c), 能够反对 (a),(a,b),(a,c),(a,b,c) 组合进行应用索引的查找,但不反对 (b),(c),(b,c) 进行查找。这就是 mysql 最左匹配准则,查问条件外面要有联结索引最右边的那个字段才会用到索引。这也对应了上述建设联结索引的 B + 树时,第一个字段是有序的,后续字段则是无序的。
联结索引比对每个列别离建索引更有劣势,因为索引建设得越多就越占磁盘空间,在更新数据的时候速度会更慢。
参考:
MySQL 的索引
数据库两个神器【索引和锁】