这是我参与更文挑战的第9天,活动详情查看: 更文挑战
前言
通过where条件来创建合适的索引只是第一步,要想设计优秀的索引应该考虑整个查询。
覆盖索引的定义
MySQL也可以使用索引来直接获取列的数据,这样就不再需要读取数据行。如果一个索引包含(或者说覆盖)所有需要查询的字段的值,我们就称之为“覆盖索引”,因为索引的叶子结点中有了已经要查询的数据,我们就没有必要再去查表获取数据了。
覆盖索引可以极大的提高性能
1.可以减少数据访问量,因为索引条目比数据行数通常小很多 2.减少随机读取的io,索引一般都是按照列值顺序存储的,会比随机从磁盘中读取每一行数据的IO要少得多。 3.引擎是InnoDB时,可以避免对主键索引的二次查询,因为直接就从索引中把数据读到了,不用回表。 索引中满足查询的成本一般比查询行要小得多。需要注意MySQL只能使用B-Tree索引来做覆盖索引。
表的数据结构
CREATE TABLE `chinese_score` (
`exam_id` int(11) NOT NULL COMMENT '考试Id ,外键',
`exam_code` int(11) NOT NULL COMMENT '考号',
`user_name` char(5) DEFAULT NULL,
`class_name` int(11) DEFAULT NULL COMMENT '班级名称',
`total_score` int(11) DEFAULT NULL,
`area_ranking` int(11) DEFAULT NULL,
`school_ranking` int(11) DEFAULT NULL,
`class_ranking` int(11) DEFAULT NULL,
PRIMARY KEY (`exam_code`) USING BTREE,
UNIQUE KEY `idx_exam_id_name` (`exam_id`,`class_name`,`user_name`) USING BTREE,
KEY `idx_total_score` (`total_score`) USING BTREE,
KEY `idx_exam_id` (`exam_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
什么时候我们使用了索引覆盖查询
比如这个sql
SELECT exam_id,class_name,user_name FROM `chinese_score` where exam_id=1
可以看到对应的解释中Extra中是Using index,这就代表了使用了覆盖索引。
InnoDB覆盖索引可以包含主键列
InnoDB有意思的一点在于可以包含不存在于索引中的主键列,因为二级索引中的叶子结点中除了索引中的值实际上也包含主键的值。 比如下面的sql
SELECT exam_id,exam_code,user_name FROM `chinese_score` where exam_id=1
exam_code并不包含在索引中,但是因为它是主键,所以我们还是可以使用 idx_exam_id_name 来做覆盖索引查询的。
总结
今天我们讲解了MySQL中的覆盖索引,明天我们还将继续介绍其他建立高性能索引的方法,敬请期待,下篇再见!