之前我们已经详细介绍了关于索引的原理和索引的查询的原则,所谓工欲善其事必先利其器,各位在学习阶段一定要要循序渐进的来学习这块知识,千万不要眼高手低,一定要不急不躁,争取一个萝卜一个坑,学完后能一次性拿下这些知识点,然后再加以运用。
前面的文章我们讨论过,索引的设计要根据 where 条件和 order by 还有 group by 后面的字段进行设计,至于原因具体在我前面的文章mysql索引的原理有详细介绍。这里我们再简单概述下。
mysql针对主键索引会维护一个b+树的结构,这个我们称之为聚簇索引,针对非主键(一般都是建立的联合索引)会对索引字段依次排序,然后从第一个字段值开始比较,第一个字段值相同就针对下一个字段值进行比较,依次往后推。
如果联合索引中的字段值都是一样的,那么就根据主键来排序。另外聚簇索引(主键索引)的b+树中保存的是一行记录的所有信息,非聚簇索引(非主键索引)仅仅保存索引字段值和主键字段值。
好了,对于索引原理的回顾我们就介绍到这里,本篇文章,我们继续介绍的是mysql设置的基本原则,这个也很好理解,就是在设计和建立索引的时候需要遵循哪些原则,按照“标准”去建立索引。今天我们就将关于索引的设计的所有的原则一次性讲清楚。
再多说几句,关于这个知识点,在面试的时候,我经常会问候选人,以此来判断他对索引是不是真的有理解,而不是简单的背八股文! 主键索引
对于主键索引其实是最简单的,但是这里有一些注意的地方还是再啰嗦下。
大家在设计主键的时候一定要是自增的,非常不建议使用uuid作为主键。
为什么?因为uuid是无序的,mysql在维护聚簇索引的时候都是按照主键的顺序排序的,也就是说每个数据页中的数据一定是按照主键从小到排序的,而且,数据与数据之前是通过单向链表连接的,上一个数据页中的最大的主键的值一定是小于下一个数据页中的最小的主键的值,数据页和数据页之间是通过双向链表来维护的。
我们还是老规矩,画个图帮助大家理解
选择区分度大的列作为索引
这又是什么意思?举个例子相信大家一下子就明白了。
假设现在有一个"性别"字段,里面存放的数据的值要么是男,要么是女,那么这样的字段很不适合作为索引。
这样的字段的值的主要特点就是区分度不够高,而区分度不高的字段不适合做索引,为什么呢?
因为如果值出现的几率几乎相等,那么无论搜索哪个值都可能得到一半的数据。
在这些情况下,还不如不要索引,因为mysql他还有一个查询优化器,查询优化器发现某个值出现在表的数据行中的百分比很高的时候,它一般会忽略索引,进行全表扫描。
惯用的百分比界线是"30%"。(匹配的数据量超过一定限制的时候查询器会放弃使用索引(这也是索引失效的场景之一哦)。
这就是原因。所以看到这里相信大家应该知道为什么要尽量避免使用基数小的字段作为索引了吧。其实这里涉及到mysql的一个专有名词【cardinality(索引基数)是mysql索引很重要的一个概念】 尽量为order by 和 group by 后面的字段建立索引
将 order by后面的字段建立索引,这样在查询的时候就不需要再去做一次排序了,因为我们都已经知道了建立索引之后在b+树中的记录都是排序好的。
group by 和 order by 其实是类似,所以将这两个放在一起说了。
因为在group by 的时候也要先根据 group by 后面的字段排序,然后在执行聚合操作。
如果 group by 后面的字段没有排序,那么这个时候mysql是需要先进行排序的,这样就会产生临时表,一个排好序的临时表,然后再在临时表中执行聚合操作,这样子当然效率很低了,如果 group by 后面的字段已经建立了索引,那么mysql 就不需要再去排序,也就不会产生临时表。
然而比较坑的是,如果 group by的列和 order by的列不一样,即使都有索引也会产生临时表,其实对于这些情况我网上搜了下好像还很多,这里我给大家列出来,说实话,这些虽然是标准,但是这个标准好像很难实现,因为实际的场景肯定没这么简单和单纯
1. 如果group by 的列没有索引,产生临时表.
2. 如果group by时,select的列不止group by列一个,并且group by的列不是主键 ,产生临时表.
3. 如果group by的列有索引,order by的列没索引.产生临时表.
4. 如果group by的列和order by的列不一样,即使都有索引也会产生临时表.
5. 如果group by或order by的列不是来自join语句第一个表.会产生临时表.
6. 如果distinct 和 order by的列没有索引,产生临时表.
7. group by 和 order by 的列一样且是主键,但select 列含有除group by列之外的列,也会产生临时表