SQL分页过多时, 如何优化
程序员文章站
2023-04-06 10:44:51
问题: 我们经常会使用到分页操作,这里有个问题,在偏移量非常大的时候,它会导致MySQL扫描大量不需要的行然后再抛弃掉。如: 上述这条SQL语句需要查询10020条记录然后只返回最后20条。前面的10000条记录都将被抛弃,这样代价非常高。 方法一、延迟关联 优化此类分类查询的一个最简单的办法就是尽 ......
问题:
我们经常会使用到分页操作,这里有个问题,在偏移量非常大的时候,它会导致mysql扫描大量不需要的行然后再抛弃掉。如:
select id, name from a order by id desc limit 10000, 20;
上述这条sql语句需要查询10020条记录然后只返回最后20条。前面的10000条记录都将被抛弃,这样代价非常高。
方法一、延迟关联
优化此类分类查询的一个最简单的办法就是尽可能地使用索引覆盖扫描(如果一个索引包含(或者说覆盖)所有需要查询的字段的值,我们就称之为“覆盖索引”。可以使用explain查看extra列信息,如果看到“using index”的信息则说明使用到了覆盖索引。),而不是查询所有的列。然后根据需要做一次关联操作再返回所需的列。对于偏移量很大的时候,这样做的效率会提升非常大。
如上述sql语句可以修改为:
select id, name from a inner join ( select id from a order by id desc limit 10000, 20 ) as tmp using(id);
这里的“延迟关联”将大大提升查询效率,它让mysql扫描尽可能少的页面,获取需要访问的记录后再根据关联列回原表查询需要的所有列。
方法二、使用书签记录上次取数据的位置
可以使用书签记录上次取数据的位置,那么下次就可以直接从该书签记录的位置开始扫描,这样就可以避免使用offset。
如上一次记录到10000为止,则可以修改为:
select id, name from a where id < 10000 order by id desc limit 20;
这种方法的好处是无论翻页到多么后面,其性能都会很好。
方法三:使用between and
有时候也可以将limit查询转换为已知位置的查询,让mysql通过范围扫描获得到对应的结果。
如知道边界值为10000,10020后上述语句可以修改为:
select id , name from a where id between 10000 and 10020 order by id desc;
除上述方法外,还有一些其它方法,如:
- 使用预先计算的汇总表
- 关联到一个冗余表,冗余表只包含主键列和需要做排序的数据列
- 使用sphinx优化一些搜索操作
上一篇: gcc 手动安装