《MySQL——使用联合索引、覆盖索引,避免临时表的排序操作》

联合索引避免临时表排序

在上一篇笔记(MySQL——order by逻辑(全字段排序与rowid排序))中,讲到查询语句查询多个字段的时候使用order by语句实现返回值是有序的,而order by是使用到了临时表的,会带来时间和空间损失。
其实使用联合索引,就可以避免临时表的排序操作。
只要保证city这个索引上取出来的行天然就是按照name递增排序的话,就可以不用再排序了。

alter table t add index city_user(city,name);

在这个索引里面,通过树搜索的方式定位到第一个满足city = '杭州’的记录,并且额外确保了,接下来按顺序取“下一条记录”的遍历过程中,只要city值是杭州,name值一定有序。
查询流程变为:
1、从索引(city,name)找到第一个满足city = '杭州’条件的主键id;
2、到主键id索引取出整行,取name、city、age三个字段值,作为结果集的一部分直接返回
3、从索引(city,name)取下一个记录主键id;
4、重复step2、3直到查到第1000条记录,或者不满足city = '杭州’条件时循环结束。

覆盖索引优化查询

可以使用覆盖索引继续优化查询的执行流程:
覆盖索引指,索引上的信息足够满足查询请求,不需要再回到主键索引上取数据。
针对select city,name,age from t 这个查询,可以创建一个city、name和age的联合索引,对应语句为:

alter table t add index city_user_age(city,name,age);

这时,对于city字段的值相同的行来说,还是按照name字段的值递增排序。查询语句的执行流程变为:
1、从索引(city,name,age)找到第一个满足city = '杭州’条件的记录,取出其中的city、name和age三个字段值,作为结果集的一部分直接返回
2、从索引(city,name,age)取下一个记录,同样取出这三个字段的值,作为结果集的一部分直接返回
3、重复步骤2,直到查到第1000条记录,或者是不满足city = '杭州’条件时循环结束。

当然,并不是说每个查询能用上覆盖索引,就要把语句中涉及的字段都建上联合索引。因为索引有维护代价。

思考

假设表里面已经有了city_name(city,name)联合索引。你需要查询杭州和苏州两个城市中所有市民的名字,并且按名字排序,显示前100条记录。

select * from t where city in('杭州','苏州') order by name limit 100;

这个语句会有排序。因为条件是苏州或杭州。如果只有一个条件如只有杭州,那么就不需要排序操作。
如果我们需要实现一个在数据库端不需要排序的方案,可以这么实现:
把这一条语句拆成两条语句,流程如下:
1、执行select * from t where city = '杭州' order by name limit 100;
(这个语句不需要排序,客户端用一个长度为100的内存数组A保存结果)
2、执行select * from where city = '苏州' order by name limit 100;
(相同的方法,结果被存入内存数组B)
3、对AB两个有序数组采用归并排序,得到name最小的前100值,这就是我们需要的结果了。

猜你喜欢

转载自blog.csdn.net/qq_42604176/article/details/115415176