关于索引的建立与使用规范,网上有很多相关的博客。这里我主要也是想自己去验证其中一些可行性。
这里我们通过执行计划分析来验证一些索引优化规范可以提高的性能可行。
这里我建立user表,并先给age字段建立索引,然后通过存储过程塞入数据。
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`phone` varchar(255) DEFAULT NULL COMMENT '电话',
`name` varchar(255) DEFAULT NULL COMMENT '姓名',
`age` int(11) DEFAULT NULL COMMENT '年龄',
PRIMARY KEY (`id`),
KEY `age_index` (`age`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
存储过程(数据量具体大小自己决定)
创建插入数据的存储过程
DELIMITER //
DROP PROCEDURE IF EXISTS `insertUser` //
CREATE PROCEDURE `insertUser`(n INT)
BEGIN
DECLARE i INT DEFAULT 100000;
WHILE i < n DO
INSERT INTO `user` VALUES (i, 13500000000+i, CONCAT('name',i), floor(1+rand()*100));
SET i = i + 1;
END WHILE;
END //
DELIMITER ;
规范列表
尽量多使用覆盖索引
可以用到覆盖索引的地方尽量使用覆盖索引。在使用普通索引的时候,我们如果需要大量的数据查询的时候,可以使用覆盖索引进行延迟关联然后减少回表的次数。
#未使用覆盖索引
select * from user where age > 50 LIMIT 5000
#使用覆盖索引
select a.* from user a,(select id from user where age > 50 LIMIT 5000) b where a.id = b.id
这里我们虽然虽然age的查询行数并没有减少,但是是可以减少我们的回表次数的。
Using index condition
这里出现说明我们要查询的字段有包括索引和没有索引的,所以需要进行回表查询。
Using where; Using index
这里Using where代表着我们在检索age字段后会进行筛选,然后使用到覆盖索引。这里将id都查出来,然后再通过id进行全字段查询。
根据最左前缀匹配原则来建立合适索引
我们知道InnoDB具有最左匹配的特性,比较出名的就是(a,b,c)联合索引的问题。所以我们在上表通过建立一个联合索引,并把其他影响的索引先删除掉。
我们以建立索引(age,name,phone)为例,来演示。
- 在查询的时候,用到索引(age,phone)用到了联合索引,但是只走a索引。
- 在查询的时候,用到索引(age,name,phone)走联合索引,顺序无关。
在和上面相比,我们可以通过filtered可以对比,发现该字段对表格符合条件的记录数的百分比悲观估计少了很多。
- 在查询的时候,用到索引(name,phone)不走索引
少了age字段,不符合最左匹配,直接进行全表扫描。
- 在遇到操作符号的时候,索引就不走了。索引我们尽量将有操作符号放在后面,将可以用到的索引放到前面。针对如此,我们在建立索引的时候就需要考虑到经常用来比较的放到联合索引的后面,哪怕它的区分度比较高。(可以看到如下就不走索引了)。
这里的操作符号包括但不限于(>,<,>=,<=)
- 还有就是在建立联合索引的时候尽量将区分度高的放在前面,可以过滤掉大量数据。比如我们在上面建立的联合索引是(age,name,phone),但是phone的区分度其实是比较高,可以考虑放在前面。不过具体顺序还是要看业务中使用的情况来定。
- 还有其他一些相关的规范,这里就不演示了。
- 在使用%进行模糊匹配的时候,尽量不要使用左模糊或者全模糊,而是使用右模糊来走索引。
- or关键字会导致索引失效,尽量放在后面以及在联合索引后面字段使用。
- 在对varchar建立索引的时候,一定要设置索引前缀长度。因为正常字符串长度20左右就可以达到90%的区分度了。而如果不设置长度的话,我们的索引结构因为一个页大小只有16kb,那么就会大大减小了数据的存放量。
存在唯一的时候尽量使用唯一索引
在之前写博客介绍索引结构原理的时候,说了一个如果数据唯一的话,我们可以用普通索引来代替唯一索引,然后在应用层面上判断唯一性约束即可。这里我们就可以减少唯一索引在插入等写操作的时候带来的额外性能损耗。 (因为唯一索引在写操作等的时候,需要在数据库判断唯一性约束,以及普通索引有buffer pool(这里详细可以看高性能mysql或者查看相关博客即可了解)进行优化)
(修正)
但是最近这里在查询相关资料的时候,都是建议业务上有唯一特性的字段的时候,都要建立唯一性约束。而上面所说的写操作等判断唯一性约束在如今数据库面前,速度损耗可以不计。而且最重要的是,哪怕我们在应用层面再进行唯一性判断的时候,在没有建立唯一性约束的时候,都有可能有脏数据的产生。
总结
关于索引的建立和使用规范有很多,很多时候规范也不一定能起到优化作用,具体的索引还是要视业务情况来建立和使用。总之很多规范是死的,但是实际上业务的优化才是活的。