今日,无意间打开了脉脉,看到了一条某大厂的一面的关于数据库的面试题。点进去看了一眼
细想一下,感觉想要答得完美还是挺不容易的,于是就赶紧做了一番实验。验证一下自己的想法,同时记录一下。
问题
数据库中4个字段id,a,b,c。其中id主键,有两个联合索引,ab,ac下面几个查询都会用到哪些索引
select * from t where a=xx and b=xx and c=xx;
select * from t where a=xx and c=xx and b=xx;
select * from t where a=xx and (b=xx or b=xx);
问题看上去貌似挺简单的,但细想又觉得好像很难回答的很全面。
首先先放上我实验后的一些结论
结论
先说结论,再通过实验来证明
01 查询条件b和c的先后顺序,不影响最终的索引选择
02 ab,ac联合索引建立的先后顺序会影响索引的选择
03 MySQL优化器会根据possible_keys中的索引键顺序选取索引,如果能满足需求则不继续选择后面的索引。possible_keys内可以选取的索引键就是安装创建顺序排列的。
04 按顺序只选取possible_keys内的第一个索引的情况包括:abc三个字段都唯一、abc三个字段都不唯一、a唯一bc不唯一。
05 当只有b和c其中一个字段唯一时,会分别选取ab或ac的组合索引。
06 or会导致索引失效,因此只有a字段能用到索引,所以第三个是索引是用到了ac组合索引中的a
以上结论部分为个人理解,可能有不对的地方,希望大家留言讨论交流。
实验验证
先建两张表t1,t2,两张表的唯一区别就是建立联合索引的顺序不同。
t1 先建ab联合索引,再建ac联合索引
t2 先建ac联合索引,再建ab联合索引
一、先建立ab联合索引,再建立ac联合索引
- a b c 都唯一
mysql> select * from t1 where a=20 and b=20 and c=20;
+----+------+------+------+
| id | a | b | c |
+----+------+------+------+
| 20 | 20 | 20 | 20 |
+----+------+------+------+
mysql> explain select * from t1 where a=20 and b=20 and c=20;
+----+-------------+-------+------------+------+---------------+--------+---------+-------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------+---------+-------------+------+----------+-------------+
| 1 | SIMPLE | t1 | NULL | ref | idx_ab,idx_ac | idx_ab | 10 | const,const | 1 | 10.00 | Using where |
+----+-------------+-------+------------+------+---------------+--------+---------+-------------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> explain select * from t1 where a=20 and c=20 and b=20;
+----+-------------+-------+------------+------+---------------+--------+---------+-------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+--------+---------+-------------+------+----------+-------------+
| 1 | SIMPLE | t1 | NULL | ref | idx_ab,idx_ac | idx_ab | 10 | const,const | 1 | 10.00 | Using where |
+----+-------------+-------+------------+------+---------------+--------+---------+-------------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
根据explain的显示结果,交换where条件中b和c的位置,对索引的选取没有影响。最终选择了使用ab联合索引。
- a b c 不唯一
不唯一的情况分为四种:
a,b,c三者都不唯一
explain结果显示都使用了idx_ab索引
a,b不唯一,c唯一
explain显示优化器最后选择了idx_ac索引。
a,c不唯一,b唯一
explain显示优化器最终选择了idx_ab联合索引
a 唯一,b,c不唯一
选择了ab联合索引,与都不唯一的情况相同
小结
1、查询条件b和c的顺序,不影响最终的索引选择
2、只有当a,b字段不唯一,c字段唯一的情况下才会选择ac联合索引,其余情况都会选择ab联合索引
二、先建立ac联合索引,再建立ab联合索引
- a b c 都唯一
根据explain的显示结果,交换where条件中b和c的位置,对索引的选取没有影响。最终选择了使用ac联合索引。
- a b c 不唯一
不唯一的情况分为四种:
a,b,c三者都不唯一
explain显示只选择了ac联合索引
a,b不唯一,c唯一
explain显示选取了ac联合索引
a,c不唯一,b唯一
显示使用了ab联合索引
a唯一,bc不唯一
显示使用了ac联合索引
小结
1、查询条件b和c的位置,不影响最终的索引选择
2、只有当a,c字段不唯一,b字段唯一的情况下才会选择ab联合索引,其余情况都会选择ac联合索引
根据这两次实验,ab和ac组合索引的创建先后顺序不同,explain显示选择的索引键的不同,证实了之前的结论。
第三个sql
select * from t where a=xx and (b=xx or b=xx);
explain显示用到的索引键为idx_ac,key_len 为5个字节,a字段类型为int,占4个字节,字段允许为空,需要用1个字节来记录。因此这里or会导致索引失效,只有a字段用到了索引。