开发中可能会遇到索引失效的状况,使用到了索引字段可是却没有利用索引查询。mysql
创建一个测试用表sql
DROP TABLE IF EXISTS index_test; CREATE TABLE index_test( t_id INT PRIMARY KEY, key1 INT, key2 INT, key3 INT, key4 INT, content VARCHAR(20) ); INSERT INTO index_test VALUES(1,1,1,1,1,'a'); INSERT INTO index_test VALUES(2,1,2,3,4,'b'); INSERT INTO index_test VALUES(3,4,1,2,3,'c'); INSERT INTO index_test VALUES(4,3,4,1,2,'d'); INSERT INTO index_test VALUES(5,2,3,4,1,'e'); CREATE INDEX index_key1_key2_key3_key4 ON index_test(key1,key2,key3,key4);
如何防止索引失效:函数
1. 最佳左前缀法则: 索引为多列时,查询条件最好从索引最左边开始,不跳过中间列。(不过能够插入别的条件,好比key=1,content = ‘a’, key2 = 2 这样,不会影响总体效率)测试
使用的是查询类型是ref(索引扫描),根据索引进行了常量查询(索引的取值是个常数),查询结果利用率是100%(只扫了符合条件的那一条数据)。优化
当使用的查询条件没有从索引的第一列开始时,查询类型变成了all(扫描全表),key = null (没有用到索引),ref = null(没有利用索引查询), 查询结果利用率只有20%(扫描了5行数据,只有一条符合条件。)spa
2. 不要在索引列上作任何操做(计算,函数,类型转换,不等于,is null, is not null)3d
把key = 1 变成了 key +1 = 2 结果同样,可是查询从索引查询变成了全表扫描。code
3. 范围查询右边的索引会失效。 blog
此时是一个范围查询,并且效率很高。索引
当key2 后面 加了 key3后,虽然条件更加精确了,可是效率反而低了。 由于key3的索引没有被使用,单独为key3进行了全表扫描。
因此这时最好创建索引顺序 key1,key3,key2, 而后把范围查询放在最后。
4. 尽可能使用索引覆盖, 少用 select * 查询
查询内容中有不是索引的列(我这个表里的content不是索引),则mysql会先找到符合条件的行,而后从表中读取数据
查询的列所有是索引内的列(不是同一个索引里的也能够),则mysql会直接从索引中读取数据。
5. 通配符不要做为字段开头,不然会致使索引失效(like '%aaa')
加一个key5用来测试
ALTER TABLE index_test ADD COLUMN key5 VARCHAR(20); UPDATE index_test SET key5 = CONCAT('test_',content,key1); CREATE INDEX index_key5 ON index_test(key5);
%放在后面,进行了索引key5的范围搜索。
%放在前面,或者两边,进行了全表搜索
解决:在实际状况中,不可避免会使用%在两边的状况,这时能够利用索引覆盖提升效率
建立复合索引key1,key2,key5,这样查询内容变为包含key5的一个索引中的内容,查询索引覆盖,变为索引查询
再加个 主键依然生效。 可是加其余索引列就不能够。
6. 新人杀手= =|| varchar字段没加 ' ',大幅拖慢速度并且很难被发现。。。
正常状况: 索引查询, 使用了key5, 常数查询。
好比有个‘2000’, 写成了 2000, 则会索引失效。变成了全表搜索
7.尽可能不要用or。
听说旧版本会致使索引失效,我试着没问题,貌似如今没事了= =?
这个通常是用union 或者 in 来优化。