MySQL 索引选择性与前缀索引(示例库)

问题

索引可以加快查询速度,那么是不是表都需要建立索引呢?

MySQL 索引选择原则分析(一)中已经介绍了,索引文件是存储在磁盘上的。因此索引虽然加快了查询速度,但是索引也是有代价的。

一、表记录比较少时,没必要建立索引。

二、索引的选择性比较低时,没必要建立索引。

索引的选择性是指不重复的索引值与表记录数的比值。

索引的选择性的取值范围为(0,1】,选择性越高的索引价值越大。

如:MySQL示例库的titles表,看一下它的选择性:

SELECT COUNT(DISTINCT(title))/COUNT(1) AS Selectivity FROM titles;

title的选择性为0.0000,所以没有必要为其单独建索引。

三、前缀索引

前缀索引是用列的前缀代替整个列作为索引key,当前缀长度合适时,可以做到既使得前缀索引的选择性接近全列索引,同时因为索引key变短而减少了索引文件的大小和维护开销。

下面以employees表为例介绍前缀索引的选择和使用。

SELECT * FROM employees WHERE first_name='Eric' AND last_name='Anido';

执行上面的SQL,时间为0.235s。

上面的SQL查询查询计划,可以看出,type为ALL,也就是全表扫描。

建<first_name>或<first_name,last_name>,看下两个索引的选择性:

SELECT COUNT(DISTINCT(first_name))/COUNT(1) AS Selectivity FROM employees;
SELECT COUNT(DISTINCT(CONCAT(first_name, last_name)))/COUNT(1) AS Selectivity FROM employees;

2句SQL的结果分别为0.0042、0.9313。<first_name,last_name>索引的选择性很好,但是长度为30,有没有兼顾长度和选择性的办法呢?也就是可以考虑用first_name和last_name的前几个字符建立索引,看一下选择性是多少:

SELECT COUNT(DISTINCT(CONCAT(first_name, LEFT(last_name, 3))))/COUNT(1) AS Selectivity FROM employees;
SELECT COUNT(DISTINCT(CONCAT(first_name, LEFT(last_name, 4))))/COUNT(1) AS Selectivity FROM employees;

查询2个SQL的结果分别为0.7879、0.9007,明显第二句SQL的选择性高出很多。

我们来建立索引:

ALTER TABLE employees ADD INDEX `first_name_last_name4` (first_name, last_name(4));

查询前面的SQL语句,执行时间为0.002。查询效率已经很明显了。

总结:

前缀索引兼顾索引大小和查询速度,但是其缺点是不能用于ORDER BY和GROUP BY操作,也不能用于Covering index(即当索引本身包含查询所有需全部数据时,不再访问数据文件本身)。

你可能感兴趣的:(MySQL 索引选择性与前缀索引(示例库))