一、聚簇索引、非聚簇索引
- 聚簇索引(Clustered Index):又称为聚集索引。将数据存储与索引放到了一起。索引结构的叶子节点保存了
行数据。必须有而且只能有一个。 - 非聚簇索引(Secondary Index):又称为非聚集索引、二级索引。将数据与索引分开存储,索引结构的叶子节点关联的是对应的
主键。可以存在多个这种索引。
聚簇索引选取规则
- 如果表中存在
主键,那么主键就是聚簇索引。 - 如果不存在主键,将使用第一个
唯一(unique)索引作为聚簇索引。 - 如果表没有主键,也没有合适的唯一索引,则InnoDB会自动生成一个
rowid作为隐藏的聚簇索引。
回表查询
通过二级索引找到对应的主键值,再到聚簇索引中查找整行数据,这个过程就是回表查询。
二、覆盖索引
覆盖索引是指查询使用了索引,并且需要返回的列,在该索引中已经全部能够找到。
- 使用ID查询,直接走聚集索引查询,一次索引扫描,直接返回数据,性能高。
- 如果返回的列中没有创建索引,有可能会触发回表查询,尽量避免使用select *.
大家看下面的例子:
| id | name | gender | createdate |
|---|---|---|---|
| 2 | Arm | 1 | 2021-01-01 |
| 3 | Lily | 0 | 2021-05-21 |
| 5 | Rose | 0 | 2021-02-14 |
| 6 | Zoo | 1 | 2021-06-01 |
| 8 | D0c | 1 | 2021-04-08 |
- id是主键,默认是主键索引。
- name字段是普通索引。
1. select * from tb_user where id = 1;
覆盖索引,因为id为聚簇索引,索引树中叶子节点保存的整行数据。
2. select id,name from tb_user where name = 'Arm';
覆盖索引,因为name的索引树中,叶子节点存储的是主键id的值,索引本身存储的name字段的值。所以通过普通索引name就可以把id,name的信息都查询出来。
3. select id,name,gender from tb_user where name = 'Arm';
非覆盖索引,因为需要分两步执行。
一、通过name索引得到id,name。二、需要进行回表查询,通过id主键索引查询到gender列。
MySQL超大分页优化处理
在数据量比较大时,如果进行limit分页查询,在查询时,越往后,分页查询效率越低。
看一下执行limit分页查询耗时对比:
因为当在进行分页查询时,如果执行limit 9000000,10,需要MySQL排序前9000010条记录,仅仅返回9000000~9000010的记录,其他记录丢弃,查询排序的代价非常大。
优化思路
分页查询时,通过创建覆盖索引能够比较好的提高性能。可以通过覆盖索引+子查询方式进行优化。
select *
from tb_sku t,
(select id from tb_sku order by id limit 9000000,10)a
where t.id = a.id;
这条sql中,子查询通过id进行排序以及查到9000000~9000010条记录都是通过id覆盖索引,这里效率就比较高了,而且又通过id覆盖索引查询整行数据。