写点什么

MVCC 导致 limit 1 执行慢测试

  • 2022 年 7 月 11 日
  • 本文字数:2086 字

    阅读完需:约 7 分钟

作者: h5n1 原文来源:https://tidb.net/blog/9ddaa53a


       本测试源于问题https://asktug.com/t/topic/664215/20


       Tidb 执行 SQL 时根据条件构建 key range,然后根据 key range 去匹配相应的 region,针对每个 region 生成一个 coprocessor task 下发到 tikv 去执行。由于 tidb  mvcc 实现原理在 DML 后保留历史版本,会导致在扫描时会读取历史版本,通过 explain analyze 的 total_process_keys 和 total_keys 的差可以判断,如果 2 者差距较大说明有较多的历史版本,可能是 GC 未完成处理或 GC 处理遇到问题。


       对于 limit 使用下推到 tikv 的优化,使每个 coprocessor task 获得达到满足 Limit 条件的数据后即停止向 tidb server 返回数据,从而避免从 tikv 扫描大量数据后返回 tidb 在由 tidb 进行 limit 过滤,从而提升 SQL 性能。


       对于全表扫描会每次下发 tidb_distsql_scan_concurrency 个 cop task 直到完成所有数据扫描,tidb 对简单的 tablescan+limit 方式做了优化,如果 limit 数量未超过 chunksize(1024),则可以根据 limit 动态调整下发 cop task 数量为 1,导致会按照 key range 顺序一个个的扫描 region:https://github.com/pingcap/tidb/issues/18791


1      测试版本

       tidb v5.3.1 (arm 平台,4 tidb+6tikv+3PD)

2      测试环境

       使用 sysbench 初始化 10 张 2 亿的表。表结构如下:




    表使用 bigint 列作为主键,会以 id 列作为 rowid,region key 会按 id 顺序递增。

3      测试方式

     每次执行相关 select 前,都 reload tikv 保证都进行物理读取, 以便对执行时间做对比。

4      测试过程

4.1     测试对比基准

       分别对 2 个表进行全表扫描和 limit 限制观察正常情况下整个全表扫描和正常 limit 执行时的资源情况。


       对 sbtest1 进行全表扫描,执行时间 3m0.2s,共执行 496 个 cop_task,total_process_keys: 200000000, total_keys: 287870027,读取 read_byte: 18.5 GB




       使用 sbtest2 表, 可以看到 limit_10 task 列为 cop[tikv] 表示已下推到 tikv。在完全没有对表做数据变更的情况下,执行时间 1.85ms,仅执行 1 个 cop_task,total_process_keys: 1,读取了 read_byte: 29.2 KB





4.2     delete 中间数据

       使用 delete from sbtest4 where id>6000 and id<20099300; 删除表中间部分数据,仅保留首、尾小部分数据。


       SQL 执行 0.1 秒,从第一个 region 中就找到了符合条件数据,仅执行 1 个 cop_task,total_process_keys: 1, total_keys: 2。





4.3     删除全部数据

       测试使用 sbtest3 表,共执行 497 个 cop_task, total_process_keys: 0, , total_keys: 412981739, 读取 19.7G。




4.4     删除表前段数据

       使用 SQL:delete from sbtest5 where id<100533351; 由于删除表中前一半数据导致按 region key 扫描数据时跳过大量历史版本,SQL 执行 2m20.1s , 共 257 个 cop_task,total_process_keys: 1, total_keys: 199986568,  total_keys: 2,读取 10.4G。



4.5     删除表后段数据

        使用 SQL:delete from sbtest6 where id>100533351; 从第一个 region 中就找到了符合条件数据,因此仅执行 1 个 cop_task,SQL 执行 8ms ,total_process_keys: 1, total_keys: 2。




      




         ![image.png](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-1651042399057.png)![](file:///C:\Users\unicom\AppData\Local\Temp\msohtmlclip1\01\clip_image020.png)
复制代码

4.6     Truncate 后测试

       使用 sbtest2 表,Truncate 后仅 1 个 region, 因此仅有 1 个 cop_task



4.7    禁用 limit 下推 tikv

       使用 sbtest7 表未做任何 DML,禁用 Limit 下推后执行计划中少了一个 cop[tikv]的 limit 算子, tikv 侧数据扫描返回 41 万行,虽然执行计划中显示 cop_task 数量为 1, 但实际下发 tidb_distsql_scan_concurrency 参数个 cop_task 到 tikv


             ![image.png](https://tidb-blog.oss-cn-beijing.aliyuncs.com/media/image-1651042417691.png)![](file:///C:\Users\unicom\AppData\Local\Temp\msohtmlclip1\01\clip_image023.png)
复制代码






调整 tidb_distsql_scan_concurrency 参数后的执行



5      测试总结

(1)   DML 后产生的 MVCC 版对 limit 执行性能会产生影响,根据数据分布情况不同,limit 的范围不同,影响大小不一样。


(2)   Truncate 表后使用 drop+create 建立新表,因此不影响 limit,对于全表删除应使用 truncate 方式,也有利于 GC 回收


(3)   Limit 不下推到 tikv 会导致扫描返回更多的结果,降低 SQL 性能,增加系统负载。

6      遗留问题

(1)   禁用 Limit 下推后,TableReader 算子基于何种算法返回 32 行?


(2)   禁用 Limit 下推后,执行计划中虽然显示为 1 个 cop task 却下发了 tidb_distsql_scan_concurrency 个 cop task?


https://asktug.com/t/topic/664580


发布于: 刚刚阅读数: 3
用户头像

TiDB 社区官网:https://tidb.net/ 2021.12.15 加入

TiDB 社区干货传送门是由 TiDB 社区中布道师组委会自发组织的 TiDB 社区优质内容对外宣布的栏目,旨在加深 TiDBer 之间的交流和学习。一起构建有爱、互助、共创共建的 TiDB 社区 https://tidb.net/

评论

发布
暂无评论
MVCC导致limit 1执行慢测试_实践案例_TiDB 社区干货传送门_InfoQ写作社区