索引是数据库中的一种非常重要的存储结构。优秀的索引对于数据库性能有着很大的提升。索引的英文是index。这个词最早的含义是书的目录。类似于下图的样子。
一本书有很多页,当我们想找一个内容的时候其实是很费时费力的,但是当我们有了索引目录以后,通过每一条索引记录中关键词和页码的对应关系,我们就可以更快的找到想要的内容。
为了加快查找速度,索引记录一定是按关键词顺序排列的,而且我们还可以建立类似下图的多级目录的结构,第一级用来索引关键词首字母,这样可以让我们快速的跳过无关的目录内容,进一步提升查找的性能。
数据库索引的作用也是类似的,本质是建立了一个数据库表中字段的值和数据存储位置的对应关系。同样,为了加速查找速度,索引记录也是按照值的顺序来排列,并且有多个层级。这个数据结构一般被实现为B+树。
最终每一条记录会指向数据的”存储位置”(这个位置是广义上的,对于不同的存储引擎,位置的实现不同)
那么我们怎么样建立数据库索引才能产生更好的性能呢。我们注意要满足以下的原则:
1. 索引要有区分度
好的索引是能够把数据均匀的分成尽可能多的子群。类似于性别这样的字段其实非常不适合做索引。因为只能把人群分成两部分,最多只能过滤一半人。考虑一下省份这个字段,如果有确定的值,可以过滤掉 95%以上的人。但是省份字段并非完美,因为每个省的人数可能不一样,有些省的人口可能人数很多,这样的的话有些情况下可能只能过滤掉90%的人,区分度有些损失。
2. 索引要有确定的值,NULL无法被索引
根据SQL标准,NULL值和其他值的比较是无法确定的。大部分情况下,NULL值无法被索引。即便SQL语句中用到了IS NULL的条件,也无法用到索引。所以如果字段中空值太多就不适合作为索引。如果一定要索引空值,可以考虑给空值一个特殊的确定值。但是仍然要考虑空值占比
3. 索引会影响更新,非越多越好
由于索引是根据数据字段的值进行排列的数据结构,数据值的修改会导致索引的更新,会有一定的性能开销,索引加的越多,性能开销越大。
4. 多个字段可以组成复合索引,但是在MySQL中要满足最左前缀匹配。
可以为多个字段建立同一个索引,索引记录中会按照这两个字段拼接起来排序。所以查询要满足最左前缀匹配,也就是说复合索引(a,b,c)可以对a=1 and b=2 and c =3和a=1 and b =2 和 a=1 这样的条件生效,但是对于 b=2 and c=3,b=2 或者c=3 这类的条件无法发挥作用。
5. 避免在字段上使用子查询
如果在字段上使用子查询的话是无法使用索引的,比如下面这一句并不能用到actor_id这个索引。
你也许会觉得Mysql会先执行in里的子查询,再使用actor_id的索引,实际上并不是这样。Mysql会对每一个actor_id执行一遍子查询,性能会比较差
如果将其改写成Join则性能会提升很多。
6. 避免在字段上使用函数
在字段上使用函数再做比较的话,是无法用到索引的,因为索引只记录了原始的值和数据位置的对应关系,并没有记录函数处理后的值。如果一定要用函数,一种处理是在数据库中直接存储函数处理以后的值,并建立索引。另一种办法是使用特殊的函数索引(需要更高的mysql版本)
希望以上的内容,对大家的日常工作能起到帮助。