数据库如果排序的话会需要先物化整个结果集,有时候合适的索引可以避免物化整个结果集。
下边我们举例说明。
表a如下:
id | name | age | sex | created_at |
---|---|---|---|---|
1 | 李一一 | 3 | 0 | 2018-09-01 12:36:50 |
2 | 张三 | 4 | 1 | 2018-09-02 12:36:50 |
3 | 小明 | 3 | 0 | 2018-09-05 12:36:50 |
4 | 李磊 | 5 | 1 | 2018-09-01 12:06:50 |
5 | 韩梅梅 | 3 | 0 | 2018-09-01 12:26:50 |
6 | 啥啥啥 | 4 | 1 | 2018-09-01 12:36:40 |
7 | 想不起来了 | 4 | 0 | 2018-09-01 15:36:50 |
8 | 你好 | 3 | 1 | 2018-09-10 15:36:50 |
9 | 恭喜发财 | 3 | 0 | 2018-09-01 12:36:45 |
10 | 阖家欢乐 | 3 | 0 | 2018-09-01 12:39:50 |
我们看这个查询
select * from a where a.age=3 order by created_at limit 2;
当执行查询时候
如果表中有索引age,索引大约是这个样子(内部实现未研究,只是写大概)
age | 数据所在地址(这里有表a的id代替) |
---|---|
3 | [1,3,5,8,9,10] |
4 | [2,6,7] |
5 | [4] |
那么数据库需要提起age=3的数据,虽然我们只需要两条,但是由于需要根据created_at进行排序,那么数据库就不得不将age=3的数据全部提取,然后进行排序,接着取符合条件的两条数据,也就是说数据库实际读取的数据是6条,如果符合条件的数据有很多,那么提取所有数据然后排序这个时间将不可忽略。
那么我们可不可以让数据库直接提取两条数据结束查询呢?
这时候我们可以创建联合索引age,created_at
那么索引的内容大约是这样子的:
在索引中,查询到age=3之后,直接顺序或倒叙查询,去除符合条件的两条数据即可。避免了取出全部数据和排序。当数据量大时,可以节省查询时间。
缺点
查询条件age不能使用区间类的,比如
select * from a where age>2 and age<5 order by created_at limit 2;
查询时仍需要提取所有符合条件的数据,然后排序。