覆盖索引:如果一个索引包含全部需要查询的字段,就称之为“覆盖索引”
举例:
- 索引(a,b)
- 查询 SELECT a,b FROM table_1;
索引包含了a,b字段,这两个字段又正好是以上查询所需的字段,因此索引(a,b)对这个查询而言是覆盖索引
覆盖索引的优点
- 索引条目通常远小于数据行大小,因此如果只需要读取索引,能够极大减少数据访问量
- 某些引擎例如MyISAM在内存中只缓存索引,不缓存数据行,因此如果需要读取数据,则需要浪费一次系统调用,覆盖索引可以避免这次开销
- (高性能MySQL原文)由于InnoDB的聚簇索引,覆盖索引对InnoDB表特别有用。InnoDB的二级索引在叶子节点中保存了行的主键值,所以如果二级主键能够覆盖查询,则可以避免对主键索引的二次查询。
EXPLAIN分析
mysql> EXPLAIN SELECT uper_date,uper_category,date_type FROM uper_all_rank WHERE uper_date='20180625';
+----+-------------+---------------+------------+------+---------------------------------+---------------------+---------+-------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+------------+------+---------------------------------+---------------------+---------+-------+-------+----------+-------------+
| 1 | SIMPLE | uper_all_rank | NULL | ref | up_date_idx,test_covering_index | test_covering_index | 42 | const | 55942 | 100.00 | Using index |
+----+-------------+---------------+------------+------+---------------------------------+---------------------+---------+-------+-------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
- 最后一列Extra写明Using index
性能简单对比
测试表uper_all_rank
表结构如下
mysql> DESC uper_all_rank;
+-------------------+---------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------+---------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| date_type | varchar(10) | NO | MUL | NULL | |
| uper_date | varchar(10) | NO | MUL | NULL | |
| uper_source | varchar(30) | NO | | NULL | |
| uper_account | varchar(200) | NO | MUL | NULL | |
| uper_uid | varchar(200) | NO | MUL | NULL | |
| uper_name | varchar(200) | NO | | NULL | |
| all_source_indexs | longtext | NO | | NULL | |
| youmi_index | decimal(10,2) | NO | | NULL | |
| uper_rank | int(11) | NO | | NULL | |
| last_rank | int(11) | NO | | NULL | |
| uper_category | varchar(50) | NO | | | |
| is_all_category | int(11) | NO | | 1 | |
| create_time | datetime | NO | | CURRENT_TIMESTAMP | |
| uper_avatar | varchar(512) | NO | | | |
+-------------------+---------------+------+-----+-------------------+----------------+
15 rows in set (0.00 sec)
mysql> SELECT count(*) FROM uper_all_rank;
+----------+
| count(*) |
+----------+
| 293196 |
+----------+
1 row in set (0.04 sec)
表索引如下
mysql> SHOW INDEX FROM uper_all_rank;
+---------------+------------+--------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------------+------------+--------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| uper_all_rank | 0 | PRIMARY | 1 | id | A | 265702 | NULL | NULL | | BTREE | | |
| uper_all_rank | 0 | date_type | 1 | date_type | A | 1 | NULL | NULL | | BTREE | | |
| uper_all_rank | 0 | date_type | 2 | uper_date | A | 17 | NULL | NULL | | BTREE | | |
| uper_all_rank | 0 | date_type | 3 | uper_source | A | 17 | NULL | NULL | | BTREE | | |
| uper_all_rank | 0 | date_type | 4 | uper_account | A | 265160 | NULL | NULL | | BTREE | | |
| uper_all_rank | 0 | date_type | 5 | is_all_category | A | 271397 | NULL | NULL | | BTREE | | |
| uper_all_rank | 1 | account_idx | 1 | uper_account | A | 87004 | NULL | NULL | | BTREE | | |
| uper_all_rank | 1 | dtype_idx | 1 | date_type | A | 1 | NULL | NULL | | BTREE | | |
| uper_all_rank | 1 | up_date_idx | 1 | uper_date | A | 15 | NULL | NULL | | BTREE | | |
| uper_all_rank | 1 | uper_uid_idx | 1 | uper_uid | A | 87023 | NULL | NULL | | BTREE | | |
+---------------+------------+--------------+--------------+-----------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
10 rows in set (0.00 sec)
添加测试索引如下
mysql> CREATE INDEX test_covering_index ON uper_all_rank (uper_date, uper_category);
Query OK, 0 rows affected (0.53 sec)
Records: 0 Duplicates: 0 Warnings: 0
EXPLAIN如下
- 非覆盖索引
mysql> explain SELECT uper_date,uper_category,date_type FROM uper_all_rank WHERE uper_date=20180625 AND uper_category='时尚';
+----+-------------+---------------+------------+------+---------------------------------+------+---------+------+--------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+------------+------+---------------------------------+------+---------+------+--------+----------+-------------+
| 1 | SIMPLE | uper_all_rank | NULL | ALL | up_date_idx,test_covering_index | NULL | NULL | NULL | 287641 | 1.00 | Using where |
+----+-------------+---------------+------------+------+---------------------------------+------+---------+------+--------+----------+-------------+
1 row in set, 5 warnings (0.00 sec)
- 覆盖索引
mysql> explain SELECT uper_date,uper_category FROM uper_all_rank WHERE uper_date=20180625 AND uper_category='时尚';
+----+-------------+---------------+------------+-------+---------------------------------+---------------------+---------+------+--------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+------------+-------+---------------------------------+---------------------+---------+------+--------+----------+--------------------------+
| 1 | SIMPLE | uper_all_rank | NULL | index | up_date_idx,test_covering_index | test_covering_index | 244 | NULL | 287641 | 1.00 | Using where; Using index |
+----+-------------+---------------+------------+-------+---------------------------------+---------------------+---------+------+--------+----------+--------------------------+
1 row in set, 5 warnings (0.00 sec)
- 查询结果
mysql> SELECT uper_date,uper_category FROM uper_all_rank WHERE uper_date=20180625 AND uper_category='时尚';
830 rows in set (0.06 sec)
SELECT uper_date,uper_category,date_type FROM uper_all_rank WHERE uper_date=20180625 AND uper_category='时尚';
830 rows in set (0.09 sec)
添加三列索引,查询条件其中两列,查询全3列字段
mysql> ALTER TABLE uper_all_rank DROP INDEX test_covering_index;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> CREATE INDEX test_covering_index ON uper_all_rank (uper_date, uper_category, date_type);
Query OK, 0 rows affected (0.59 sec)
Records: 0 Duplicates: 0 Warnings: 0
- 索引(uper_date, uper_category, date_type)
mysql> EXPLAIN SELECT uper_date,uper_category,date_type FROM uper_all_rank WHERE uper_date='20180625';
+----+-------------+---------------+------------+------+---------------------------------+---------------------+---------+-------+-------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+------------+------+---------------------------------+---------------------+---------+-------+-------+----------+-------------+
| 1 | SIMPLE | uper_all_rank | NULL | ref | up_date_idx,test_covering_index | test_covering_index | 42 | const | 55942 | 100.00 | Using index |
+----+-------------+---------------+------------+------+---------------------------------+---------------------+---------+-------+-------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
26320 rows in set (0.04 sec)
- 索引(uper_date, uper_category)
mysql> EXPLAIN SELECT uper_date,uper_category,date_type FROM uper_all_rank WHERE uper_date='20180625';
+----+-------------+---------------+------------+------+---------------------------------+-------------+---------+-------+-------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------------+------------+------+---------------------------------+-------------+---------+-------+-------+----------+-------+
| 1 | SIMPLE | uper_all_rank | NULL | ref | up_date_idx,test_covering_index | up_date_idx | 42 | const | 50808 | 100.00 | NULL |
+----+-------------+---------------+------------+------+---------------------------------+-------------+---------+-------+-------+----------+-------+
1 row in set, 1 warning (0.00 sec)
26320 rows in set (0.05 sec)
总结
不确定数据量更大的时候是否会差异更明显