Cardinality
Cardinality数值表示了该索引字段的重复率程度,数值越大代表重复率越低,PRIMIARY是自增的,能够保证插入/更新数据按照磁盘顺序进行,但是id字段因为没有什么可筛选的含义,不能进行筛选查询。
我们为data_unique_key建立了一个唯一索引,这个属性的值是一些筛选字段的md5值,如果是具体查询某一条数据的话,可以md5后查询data_unique_key为该值,速度很快。
对于重复率非常大的字段,探索一下为a建立索引是否有必要。
a的Cardinality是21
b的Cardinality是77
c的Cardinality是1305
最左匹配原则
ALTER TABLE test ADD INDEX index (a, b, c);
假设现在有一张test表,我们先建立一个联合索引,索引包含a,b,c3个字段。
我们建立的索引是3个字段联合的,但是查询的时候只用两个字段进行筛选,也会使用这个索引的前两个字段进行筛选。
还是使用两个字段进行筛选,只是用了c而不是b,查询使用了index这个索引但是key_len是202,说明只用了a的索引部分。这现象是“最左匹配原则”带来的。也就是说要像最大化利用索引,筛选的时候要根据建立索引的字段顺序就行查询,如果where等筛选/分组/排序操作能命中索引的部分顺序字段,则也会使用这部分顺序字段进行索引。
SELECT中有索引的字段,优化器会选择使用索引查询,所以查询出来的结果是以page_name排序的。
反之,如果SELECT中没有索引字段,或者只有部分包含,或者是查询 * ,都不会使用索引进行查询
a是否有必要成为索引字段
SELECT a, e FROM test WHERE a = '2';
(这个时间应该是利用了缓存的基础上的时间,第一次进行全表查询的时间是7秒多,同样的sql再次查询就变成了1+秒,试过将query_cache_type和query_cache_size都设置为0,还是这样,有说法是操作系统级别的缓存是无法限制的。如果一开始就建立索引,并SELECT a FROM test,也是六七秒,所以怀疑查询后都会有缓存,那么以下的时间都是在这个基础上进行截图)
建立一个联合索引
ALTER TABLE test ADD INDEX index(`a, b, c`);
-- SQL1:
SELECT a, e FROM test WHERE a = '1' ;
-- SQL2:
SELECT a, e FROM test WHERE a = '1' AND b = 2;
-- SQL3:
SELECT a, e FROM test WHERE a = '1' AND data_type = 2 AND c = 'math';
发现了只利用索引的一个字段进行查询,查询花费的时间比全表查询还要慢很多,但是索引字段利用率大,查询花费的时间就很少了。
删除上面建立的索引,再建立一个不包含a的索引
ALTER TABLE test
DROP INDEX index,
ADD INDEX index(b, c);
SQL1的执行如下:
相当于查询type是all,耗时比之前的包含a索引的快
同样的SQL2,可以看到索引利用长度是1,但是速度是几乎一样的,这里可以看出来a的重复率太高,是索引这个字段的意义并不大,而且会增加索引key的长度,带来B+Tree每一个节点的键值存储量减少,树的结构可能会更深,进而查询更慢。
总结:
- 联合索引中每一个索引代表的权重是不一样的,比如索引(a, b, c),a是百,b是十,c是个位,那么假设筛选条件是b和c,根据B+Tree结构,索引得到的最终是分散的,所以使用索引的意义就不大,自然就不会使用索引了
- 建立的索引字段需要充分利用,不恰当的使用可能会比全表查询来的更慢
- 为Cardinality很小的字段建立索引的必要性有待商榷,一般情况下重复率很大的字段不需要建立索引。
(以上截图都模糊掉自身数据,用a,b,c来代替)
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。