MySQL大数据量的分页查询优化

目录

  • 背景
  • 数据准备
  • 不同查询条件下耗时测试
    • `limit` 查询不同的数据记录条数测试
    • `limit` 查询不同的数据偏移量测试
  • 优化方法
    • 先拿访问数据行的主键,主键再查询所需数据
    • 定位分页查询的主键的范围,主键再查询所需数据
      • 另外的写法
    • 特殊说明
  • 总结

背景

随着业务发展越来越快,原来的数据库数据从几万突破到几百万,分页的查询策略是否需要调整一下?

数据准备

  • 表名:order_history
  • 描述:某个业务的订单历史表
  • 主要字段:unsigned int idtinyint(4) int type
  • 字段情况:该表一共 37 个字段,不包含 text 等大型数据,最大为 varchar(500)id 字段为索引,且为递增
  • 数据量:5709294
  • MySQL 版本:5.7.16

不同查询条件下耗时测试

对于一般最基本的分页查询会使用

select * from orders_history where type=8 limit 1000,10;

limit 查询不同的数据记录条数测试

select * from orders_history where type=8 limit 10000,1;
select * from orders_history where type=8 limit 10000,10;
select * from orders_history where type=8 limit 10000,100;
select * from orders_history where type=8 limit 10000,1000;
select * from orders_history where type=8 limit 10000,10000;

三次查询耗时时间如下:

  • 查询 1 条记录:3072ms 3092ms 3002ms
  • 查询 10 条记录:3081ms 3077ms 3032ms
  • 查询 100 条记录:3118ms 3200ms 3128ms
  • 查询 1000 条记录:3412ms 3468ms 3394ms
  • 查询 10000 条记录:3749ms 3802ms 3696ms

结论:在查询记录数量低于 100 时,查询耗时时间基本没有差距,随着查询记录数量越来越大,所花费的时间也会越来越多

limit 查询不同的数据偏移量测试

select * from orders_history where type=8 limit 100,100;
select * from orders_history where type=8 limit 1000,100;
select * from orders_history where type=8 limit 10000,100;
select * from orders_history where type=8 limit 100000,100;
select * from orders_history where type=8 limit 1000000,100;

三次查询耗时时间如下:

  • 查询 100 偏移:25ms 24ms 24ms
  • 查询 1000 偏移:78ms 76ms 77ms
  • 查询 10000 偏移:3092ms 3212ms 3128ms
  • 查询 100000 偏移:3878ms 3812ms 3798ms
  • 查询 1000000 偏移:14608ms 14062ms 14700ms

结论:随着查询偏移量的增大,尤其查询偏移大于 10 万以后,查询时间急剧增加。这种分页查询方式会从数据库第一条记录开始扫描,所以越往后,查询速度越慢,而且查询的数据越多,也会拖慢总查询速度

优化方法

先拿访问数据行的主键,主键再查询所需数据

这种方式适用于主键 id 递增的情况

select * from orders_history where type=8 limit 100000,1;

select id from orders_history where type=8 limit 100000,1;

select * from orders_history where type=8 and id>=(select id from orders_history where type=8 limit 100000,1) limit 100;

select * from orders_history where type=8 limit 100000,100;

四条语句的查询时间如下:

  • 1 条语句:3674ms
  • 2 条语句:1315ms
  • 3 条语句:1327ms
  • 4 条语句:3710ms

原因分析:通过使用覆盖索引查询返回需要的主键,再根据主键获取原表需要的数据

定位分页查询的主键的范围,主键再查询所需数据

这种方式假设数据表的 id 是连续递增的,则根据查询的页数和查询的记录数可以算出推查询的 id 的范围,可以使用 between and 来查询

select * from orders_history where type=2 and id between 1000000 and 1000100 limit 100;

这种查询方式能够极大地优化查询速度,基本能够在几十毫秒之内完成。限制是只能使用于明确知道 id 的情况,不过一般建立表的时候,都会添加基本的 id 字段,这为分页查询带来很多便利

另外的写法

select * from orders_history where id >= 1000001 limit 100;

当然还可以使用 in 的方式来进行查询,这种方式经常用在多表关联的时候进行查询,使用其他表查询的 id 集合,来进行查询

select * from orders_history where id in (select order_id from trade_2 where goods = 'pen') limit 100;

特殊说明

  • 一般情况下,在数据库中建立表的时候,强制为每一张表添加 id 主键字段,这样方便查询
  • 如果像是订单库等数据量非常庞大,一般会进行分库分表。这个时候不建议使用数据库的 id 作为唯一标识,而应该使用分布式的高并发唯一 id 生成器来生成,并在数据表中使用另外的字段来存储这个唯一标识

总结

要提高数据库查询的效率,关键就是利用索引树,而索引又分为普通索引和主键索引。最佳的查询效率就是要使用主键索引;而使用了普通索引又增加了一次回表查询。在大数据量的分页查询中,核心就是利用好主键索引而已

关于 mysql 索引的文章:https://blog.csdn.net/weixin_38192427/article/details/111872683

你可能感兴趣的:(#,mysql,数据库,mysql)