共计 2335 个字符,预计需要花费 6 分钟才能阅读完成。
背景
最近频繁呈现慢 SQL 导致系统性能问题,于是决定针对索引进行一些优化。一些表构造自身曾经有了不少索引,如果再持续增加索引,势必会影响到插入数据的性能。那么,是否能够应用组合索引来达到目标呢?这篇文章咱们来一探到底。
意识复合索引
如果 where 条件中应用到多个字段,并且须要对多个字段建设索引,此时就能够思考采纳复合索引(组合索引)。比方查问地址时须要输出省、市,那么在省、市上建设索引,当数据量大时会明显提高查问速度。
组合索引有啥劣势呢?
- 缩小查问开销:建设复合索引(c1,c2,c3),实际上相当于建设了(c1),(c1,c2),(c1,c2,c3)三个索引。对于大表来说,能够极大缩小开销。
- 笼罩索引:MySQL 能够间接通过遍历索引获得数据,而无需回表,缩小了很多的随机 io 操作。
- 效率高:索引列越多,通过索引筛选进去的数据就越少,从而晋升查问效率。
毛病:
- 索引字段越多,创立的索引越多,每个索引都会减少磁盘空间的开销;
- 索引越多对查问效率晋升越高,但对须要更新索引的增删改操作会有效率影响;
复合索引应用倡议:单表最好不要超过 1 个复合索引,单个复合索引最好不超过 3 个字段。一旦超过,就须要思考必要性和是否有其余代替计划。
最左匹配准则
复合索引听从最左匹配准则,顾名思义, 在组合索引中,最左侧的字段优先匹配 。因而,在创立组合索引时,where 子句中应用最频繁的字段放在组合索引的最左侧。
辅助索引是 B + 树实现的,尽管能够指定多个列,然而每个列的比拟优先级不一样,写在后面的优先比拟高。一旦呈现脱漏,在 B + 树上就无奈持续搜寻了(通过补齐等措施解决的除外),因而是依照最左间断匹配来的。既然是在 B + 树上搜寻,对于条件的比拟天然是要求准确匹配(即 ”=” 和 ”IN”)。
在 where 子句中用到两个字段 c1 和 c2,那么创立索引时,两个字段的程序应该是(c1,c2)还是(c2,c1)呢?
正确的做法是: 把反复值起码的放后面 。比方,95% 的值都不反复,则可思考放最后面。
字段程序的影响
复合索引听从最左匹配准则,那么在 where 查问条件中的字段是否也须要依照索引的程序来写呢?
比方,复合索引为(c1,c2,c3),上面两个查问条件是否会对索引有影响呢?
select * from t_user where c1 = 1 and c2 = 4;
select * from t_user where c2 = 4 and c1 = 1;
看到有文章提出第一条 SQL 语句的效率更高,是否可信?两种查问形式条件一样,后果也应该一样,失常来说 Mysql 也会让它们走同样的索引。
通过 Mysql 的查问优化器 explain 剖析上述两个条语句,会发现执行打算完全相同。也就是说:SQL 语句中的字段程序并不需要与复合索引字段程序统一,查问优化器会主动调整程序 。
如果说有效率影响,那么也就是查问优化器改正程序的影响吧,简直能够忽略不计。
单字段是否能够触发索引?
对于复合索引为(c1,c2,c3),相当于(c1),(c1,c2),(c1,c2,c3)三个索引,如果查问条件中只有 c1,很显然是会走索引的。
但如果 where 条件如下呢:
from t_user where c2 = 4;
上述语句是否会走索引呢?这得分几种状况来阐明。
执行 explan 查问 c1 为条件的 SQL 语句:
explain select * from t_user where c1 = 1;
上述语句走的索引类型为:ref。ref 类型示意 Mysql 会依据特定的算法疾速查找到符合条件的索引,而不会对索引中每一个数据都进行扫描判断。这种类型的索引为了疾速查出数据,索引就须要满足肯定的数据结构。
执行 explan 查问 c2 为条件的 SQL 语句:
explain select c2 from t_user where c2 = 4;
上述语句走的索引类型为:index。index 类型示意 Mysql 会对整个索引进行扫描,只有是索引或索引的一部分 Mysql 就可能会采纳 index 方类型的形式扫描。因为此种形式是一条数据一条数据查找,性能并不高。
在这个例子中, 对查问的字段有肯定的要求,where 中条件为 c2,select 中查问出的字段也只能是 c2,才会走 index 类型的索引 。
如果将 c2 换成 * 或其余字段:
explain select * from t_user where c2 = 4;
上述语句会发现,不再走 index 索引,而是走全表扫描了。这也从侧面阐明了 Mysql 为什么要讲最左匹配准则了。
所以论断是: 如果单个字段为复合索引的首个字段,则会失常走索引;如果单个字段是复合索引的其余字段,且仅有该字段呈现在 select 前面,则会走 index 类型索引;而其余状况,则走全表扫描 。
复合索引能够代替繁多索引吗?
繁多索引:(c1),复合索引:(c1,c2)。
当 c1 作为查问条件时,繁多索引和复合索引查问速度简直一样,甚至比复合索引还要略快。
如果仅用复合汇集索引的非起始列(c2)作为查问条件的话,复合索引是不起任何作用的。
对于一张表来说,如果有复合索引(c1,c2),则无需再建繁多索引(c1)。
如果曾经存在繁多索引(c1),因查问所需,可增加复合索引(c1,c2)来晋升效率。
小结
本篇文章整顿了 Mysql 复合索引应用时所需注意的一些知识点,在应用时能够通过 explain 来查看一下你的 SQL 语句是否走了索引,走了什么索引。
但还要理解的是:Mysql 的执行打算和查问的理论执行过程并不齐全吻合。
别问我为什么晓得,因为在实践中遇到过。同一条 SQL 语句,查问条件不同,有可能会走索引,也有可能不会走索引。
博主简介:《SpringBoot 技术底细》技术图书作者,热爱钻研技术,写技术干货文章。
公众号:「程序新视界」,博主的公众号,欢送关注~
技术交换:请分割博主微信号:zhuan2quan