暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PolarDB MySQL · 功能特性 · 大表分页查询优化

lc 2023-07-01
266

在社区MySQL中,业务如果对大表做深度分页查询往往性能很差,查询的响应时间很难满足业务的需求。PolarDB MySQL对深度分页场景优化,可以极大提升分页查询性能。

社区MySQL深度分页

我们基于TPCH(Scale 10)的表举例,比如业务对订单明细表(lineitem表)按照特定发货日期(l_shipDATE列)范围查询订单明细信息。 如果100行每页,我们查询1万页以后的查询如下:

SELECT *
FROM   lineitem
WHERE  l_shipdate > '1997-01-01'
       AND l_shipdate < '1997-08-01'
ORDER  BY l_shipdate
LIMIT  1000000, 100;

在社区MySQL中,我们可以看到如下执行计划,选择了列l_shipDATE的索引,利用索引序不需要做额外的sort操作。

mysql> explain select * from lineitem where l_shipDATE >'1997-01-01' and l_shipDATE < '1997-05-01' order by l_shipDATE limit 1000000, 100\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: lineitem
   partitions: NULL
         type: range
possible_keys: i_l_shipdate
          key: i_l_shipdate
      key_len: 4
          ref: NULL
         rows: 5820160
     filtered: 100.00
        Extra: Using index condition

在PolarDB中对optimizer_switch做如下设置,可以得到社区MySQL的执行计划。
mysql> set @@optimizer_switch='limit_offset_pushdown=off,detach_range_condition=off';

上述深度分页查询,当完全是冷数据的时候需要48.77s,全在内存中时候耗时也需要4.99s。这对于使用该业务的客户,等待时间就很难接受。

mysql> select * from lineitem where l_shipDATE >'1997-01-01' and l_shipDATE < '1997-05-01' order by l_shipDATE limit 1000000, 100;

而且该时间会随着数据量的增加而大幅增加,当200万行数据的时候冷数据要63.17s,热数据要10.04s。这里冷数据没有线性增加是因为物理IO因为已经读取的page在后面被使用而没有线性增加。如果是InnoDB buffer pool相比读取数据小,比如这里200万行的读取,设置Buffer pool size为128M,那么执行时间就需要225s。

mysql> select * from lineitem where l_shipDATE >'1997-01-01' and l_shipDATE < '1997-05-01' order by l_shipDATE limit 2000000, 100;

MySQL中所有的分页操作都会从存储引擎中将数据行逐行取出,上面的查询还要回表取非索引列数据,然后交给SQL层,SQL层检查条件,然后将不需要返回给客户端的offset数据过滤掉。

offset_1

PolarDB深度分页

在PolarDB中,优化器会分析深度分页查询的谓词条件,如果谓词条件能够在引擎的扫描范围中体现,那么就会把谓词条件的检查完全下推到引擎层,从SQL层移除。上面场景中移除谓词条件后,PolarDB会把分页数据中offset的扫描也下推到引擎层,做快速的扫描过滤。同时如果需要回表访问,PolarDB会仅对最后需要返回客户端数据做回表,极大的减少开销。

offset_2

上面的查询在PolarDB中默认计划如下:

mysql> explain select * from lineitem where l_shipDATE >'1997-01-01' and l_shipDATE < '1997-05-01' order by l_shipDATE limit 1000000, 100\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: lineitem
   partitions: NULL
         type: range
possible_keys: i_l_shipdate
          key: i_l_shipdate
      key_len: 4
          ref: NULL
         rows: 5820160
     filtered: 100.00
        Extra: Using limit-offset pushdown

在PolarDB中冷数据100w行深度分页执行时间0.21s,热数据执行主要0.07s。 对于200w行的深度分页,冷数据执行时间0.41s,热数据执行时间0.15s。当设置Buffer pool size为128M的时候,执行时间依然为0.15s,因为PolarDB 分页的200w行数据是不需要查询主键的,能够避免大量的随机IO,BP能够缓存大量二级索引数据。

性能对比总结

 100w行深度分页冷数据100w行深度分页热数据200w行深度分页冷数据200w行深度分页热数据200w行深度分页低BP size
社区MySQL48.77s4.99s63.17s10.04s225s
PolarDB MySQL0.21s0.070.41s0.15s0.15s
PolarDB MySQL提升232倍71倍154倍67倍1500倍

上面可以看到在通过索引深度分页查询表上各个列信息情况下,PolarDB MySQL可以有67到200倍以上的性能提升,对于Buffer pool size小于数据大小的场景可以有更大的提升。在不需要回表,仅查询二级索引列的场景,热数据情况下PolarDB也可以有6倍性能提升。可参加PolarDB MySQL深度分页优化的官网功能介绍文档

「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论