1.最左前缀原则
一般在where条件中两个及以上字段时,我们会建联合索引。若查询语句:select name,address,country from people where name='XXX' and country='XXX';
索引建立有下面两种方案 A(name,country) B(country,name)。将选择性好的字段放在前面(因为people name重复率相对于country低),所以应该建name,country索引。无论where name='XXX' and country='...' 还是 where country='XXX' and name='...',MySQL会帮你优化查询条件,不用担心查询顺序。若组合索引有四五个字段,那么按照选择性进行排列,选择性好的字段放前面。
假设create index idx_name_address_country on t1(name,address,country);按照最左匹配有下面几个原则,判断查询是否会走索引
1.1 若查询的条件不包含索引的最左列,无法使用索引
where name=xxx and address=xxx and country=XXX
可以走索引
where name=xxx
可以走索引
where name=xxx and country=XXX
可以走部分索引
where address=xxx
不可以走索引,不包含最左列name
where country=xxx and name=xxx
不可以走索引,不包含最左列name,mysql没有优化是因为索引字段里还包含了address
1.2 查询包含了索引中所有的字段,查询效率较高,如果只包含了索引中部分字段,查询效率会低一些
where name=xxx 和 where name=xxx and country=XXX 虽然都包含了索引最左列,也可以走索引,但是他们都只能根据name字段进行过滤数据,效率比 where name=xxx and address=xxx and country=XXX低很多
1.3 如果组合索引中已经包含了字段,可以不用单独再建索引,提高索引使用率
比如已经有了索引(name,address,country),就不需要在单独建索引(name)或 (name,address)
1.4 无法对组合索引中多个字段进行范围查询,只能按照最左原则,对最左边第一个范围查询有效
例如create index idx_A_B_C on table(A,B,C); 红字表示不走索引
A=5
索引
A BETWEEN 5 AND 10
索引
A=5 AND B BETWEEN 5 AND 10
索引
A BETWEEN 5 AND 10 AND B=5
部分索引
A IN (1,2,3) AND B=5
索引
B=5 AND ...
不走索引
A = 5 AND B > 5 AND C > 10
部分索引
1.5 覆盖索引: 即索引中包含了查询中的所有字段,可以避免回表查询,减少访问磁盘次数
1.6 利用索引的有序性,进行排序,有效减少CPU开销,需要遵从最左原则
采用idx_A_B_C,下列查询可使用索引
ORDER BY A
ORDER BY A,B
ORDER BY A DESC, B DESC
WHERE A = 5 ORDER BY B [ASC\DESC]
WHERE A > 5 ORDER BY A [ASC\DESC]
WHERE A = 5 ORDER BY A,B
ORDER BY B
ORDER BY A[ASC\DESC] ,B [DESC/ASC]
1.7 其他设计
Join查询中连接字段建立索引
只返回需要的字段,避免使用select *
不使用全模糊查询 like '%xxx%’(无法走索引),可以使用like 'XXX%'(走索引)
不等于查询not in , =(无法走索引)
类型不匹配,比如存了数值的字符串类型字段(如手机号),查询时记得不要丢掉值的引号,否则无法用到该字段相关索引
2.最大选择性原则
该不该在一个字段上建立索引,主要考虑选择性,选择性就是这个字段里面的值重复率高不高。公式是 distinct(建索引的列)/count(*) ,区间范围在[0,1],如果是0,表示该列中所有值都一样,如果是1,表示该列有唯一约束。该比例越趋向于1,查询性能越好。这是由B+Tree的性质决定的。一般情况,status(状态)、is_deleted(是否删除)、sex(性别)列都不建议建索引。单号、userid等建议放在最前面。
3.总结
索引设计的规约(摘自蚂蚁金服&集团DB设计规范)
索引不是越多越好,越多的索引带来的就是更高的索引维护成本,包含CPU计算消耗,索引建立时增加的IO开销等,因此一定要合理建立索引;
表被索引列必须定义为not null,并设置default值;
超过三个表禁止join。需要join的字段,数据类型保持绝对一致;多表关联查询时,保证被关联的字段需要有索引;
在varchar字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本区分度决定索引长度。一般对字符串类型数据,长度为20的索引,区分度会高达90%以上,可以使用count(distinct left(列名, 索引长度))/count(*)的区分度来确定。
页面搜索严禁左模糊或者全模糊,如果需要请走搜索引擎来解决。索引文件具有B-Tree的最左前缀匹配特性,如果左边的值未确定,那么无法使用此索引;
如果有order by的场景,请注意利用索引的有序性。order by 最后的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现file_sort的情况,影响查询性能。正例:where a=? and b=? order by c; 索引:a_b_c 反例:索引中有范围查找,那么索引有序性无法利用,如:WHERE a>10 ORDER BY b; 索引a_b无法排序。