分类
InnoDB的索引分为两大类:聚集索引与普通索引。
InnoDB规定每个表都必须有聚集索引:
- 如果定义了PK,那么PK就是聚集索引
- 如果没有定义,第一个非空 unique列就位聚集索引
- 如果再没有,会自动生成一个row-id作为聚集索引
结构
索引的结构为B+树
- 聚集索引:非叶子节点存储key,叶子节点存储行记录
- 普通索引:非叶子节点存储key,叶子节点存储value值
- 索引包含null:放在B+树的最左边
举例:
t(id PK, name KEY, sex, flag);
表中有四条记录:
1, shenjian, m, A
3, zhangsan, m, A
5, lisi, m, A
9, wangwu, f, B
聚集索引
上图(聚集索引)id为PK,叶子节点存储了所有的行记录
普通索引
上图(普通索引)name为普通索引,叶子节点存储了PK值。
所以对于普通索引,需要二次查找,先通过普通索引找到PK,再通过PK找到所有行记录。
索引中存在null的情况
上图为索引包含null的情况,放于最左边。
后记:覆盖索引
limit 用法
//语句一:从该参数(0)的下一条数据开始,第二个参数表示每次返回的数据条数。
select * from A limit 0,3;
语句一执行结果
//语句二:从第101条开始,读10条数
select * from B limit 100,10;
//语句三:从表的第2条开始,读10条
select * from C limit 10 offset 1
//等价于
select * from C limit 1,10
那么问题来了,如果一条SQL长这个样子:select * from C limit 100000,10
offset特别大,必然慢SQL,dba会call you!
怎么解决呢?
- 延迟加载(TODO具体怎么做,暂时没查过)
- 假设有以下SQL有组合索引(sex,score)
//方式一:
select <col> from A where sex = 'M' order by score limit 100000,10
改写为
//方式二:
select <col> from A inner join(select id from A where a.sex = 'M' order by score limit 100000,10) as a using(id)
方式一:同样是用到了联合索引,
方式二:这里利用了覆盖索引,先从覆盖索引中获取100010个id,在丢掉前100000条id,保留最后10个;
EXPLAIN各个含义解析TODO