索引选择性就是结果个数与总个数的比值。
用sql语句表示为:java
SELECT COUNT(*) FROM table_name WHERE column_name/SELECT COUNT(*) FROM table_name
通常来讲(例如书 “SQL Tuning“),若是选择性超过 20% 那么全表扫描比使用索引性能更优。
但MySQL是没有计算索引的选择性的,只是预测逻辑IO操做的数量,所以对于MySQL索引要慎重选择。
举个栗子,tinyint类型的列,用以保存性别,就算用上“保密”和“变性”2项,选择性也最小也才25%,所以也就没有设置索引的必要了。sql
假设test表中有a,b,c三个列。bash
ALTER TABLE test ADD INDEX abc(a,b,c);
至关于分别创建了
a,b,c
a,b
a
这样的3组索引,也是“最左前缀”这个规则的结果。
举个使用该组合索引的栗子:性能
SELECT * FROM test WHERE a="1" AND b="2" SELECT * FROM test WHERE a="1"
如下则用不到索引:ui
SELECT * FROM test WHERE b="1" AND c="2" SELECT * FROM test WHERE c="1"
所以组合索引有必定优点,但在使用上需谨慎。spa
MySQL 前缀索引能有效减少索引文件的大小,提升索引的速度。可是前缀索引也有它的坏处:MySQL 不能在 ORDER BY 或 GROUP BY 中使用前缀索引,也不能把它们用做覆盖索引(Covering Index)。
语法以下:code
ALTER TABLE table_name ADD KEY column_name(prefix_length);
创建前缀索引的关键在于"prefix_length"这个参数,而且前缀索引的选择性上也有一点特殊。
前缀索引的选择性公式为:SELECT COUNT(DISTINCT column_name)/COUNT(*) FROM table_name
继续举栗子!
如今有个user表,列 family_name varchar(50) 保存的是英文姓氏(我也想用中文姓名来举例,可是不大适合,看下去就明白了。。。)
要取得设置前缀索引最理想的"prefix_length",咱们首先要取得整列的选择性,以下:索引
SELECT COUNT(DISTINCT family_name)/COUNT(*) FROM user;
假设这里获得值是0.188。
而后咱们继续去看看该列前1个字符的选择性又是多少string
SELECT COUNT(DISTINCT LEFT(family_name,1))/COUNT(*) FROM user;
假设这里获得的结果是0.532,和整列的选择性出入太大,不可取,继续:it
SELECT COUNT(DISTINCT LEFT(family_name,2))/COUNT(*) FROM user; SELECT COUNT(DISTINCT LEFT(family_name,3))/COUNT(*) FROM user; ...
假设直接到“prefix_length”为5时,获得的值为0.189,很是接近!
而取6时获得的值为0.18891,这个选择性和5并无太大的误差。
再结合减小索引文件大小的这个思路
“prefix_length”值设置为5才是此处设置前缀索引的最优方案!
选择性讲完,还得再讲清楚这个前缀索引该怎么用!
书接上面的栗子~
正确的用法以下:
SELECT * FROM user WHERE family_name LIKE "lee%"; SELECT * FROM user WHERE family_name LIKE "david%";
如下则用不上该索引:
SELECT * FROM user WHERE family_name LIKE "_ee%"; SELECT * FROM user WHERE family_name LIKE "%en%"; SELECT * FROM user WHERE family_name LIKE "%ar%";
注意:SQL的模式缺省是忽略大小写的! 另外,“_”表明一个字符,“%”表明任意多个字符!