order by id limit 100 limit 下推没有生效

为提高效率,请提供以下信息,问题描述清晰能够更快得到解决:

【概述】 场景 + 问题概述
由于需要把TiDB 里面的数据导入到Hive 做一些分析,表里面有大字段,100行记录差不多2MB 的大小,采用 select * from t where id>=xx order by id limit 100 的导入。

select * from risk_event_log where id>=100 order by id limit 100; 这个SQL在 tidb server 节点产生了20MB/s 的in 流量,出的流量是2MB/S,流量放大了10倍

select * from risk_event_log where id>=100 and id<=4000 order by id limit 100; 这个SQL在 tidb server 节点只产生了2MB/s 的in 流量,出的流量是2MB/S,符合预期。

mysql> explain analyze select *  from risk_event_log where id>=100 and id<=4000  order by id limit 100;
+-----------------------------+---------+---------+-----------+----------------------+------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------+------+
| id                          | estRows | actRows | task      | access object        | execution info                                                                                                                           | operator info                     | memory  | disk |
+-----------------------------+---------+---------+-----------+----------------------+------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------+------+
| Limit_11                    | 100.00  | 100     | root      |                      | time:29.8ms, loops:2                                                                                                                     | offset:0, count:100               | N/A     | N/A  |
| └─TableReader_21            | 100.00  | 100     | root      |                      | time:29.8ms, loops:1, cop_task: {num: 1, max: 24.5ms, proc_keys: 109, tot_proc: 6ms, rpc_num: 1, rpc_time: 24.5ms, copr_cache: disabled} | data:Limit_20                     | 1.64 MB | N/A  |
|   └─Limit_20                | 100.00  | 100     | cop[tikv] |                      | tikv_task:{time:4ms, loops:3}                                                                                                            | offset:0, count:100               | N/A     | N/A  |
|     └─TableRangeScan_19     | 125.00  | 109     | cop[tikv] | table:risk_event_log | tikv_task:{time:4ms, loops:3}                                                                                                            | range:[100,4000], keep order:true | N/A     | N/A  |
+-----------------------------+---------+---------+-----------+----------------------+------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------+------+
4 rows in set (0.03 sec)

mysql> explain analyze select *  from risk_event_log where id>=100  order by id limit 100;
+-----------------------------+---------+---------+-----------+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------+------+
| id                          | estRows | actRows | task      | access object        | execution info                                                                                                                                            | operator info                     | memory  | disk |
+-----------------------------+---------+---------+-----------+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------+------+
| Limit_11                    | 100.00  | 100     | root      |                      | time:83.3ms, loops:2                                                                                                                                      | offset:0, count:100               | N/A     | N/A  |
| └─TableReader_21            | 100.00  | 100     | root      |                      | time:83.3ms, loops:1, cop_task: {num: 1, max: 79.1ms, proc_keys: 224, tot_proc: 35ms, tot_wait: 19ms, rpc_num: 1, rpc_time: 78.9ms, copr_cache: disabled} | data:Limit_20                     | 26.2 MB | N/A  |
|   └─Limit_20                | 100.00  | 100     | cop[tikv] |                      | tikv_task:{time:9ms, loops:3}                                                                                                                             | offset:0, count:100               | N/A     | N/A  |
|     └─TableRangeScan_19     | 100.00  | 224     | cop[tikv] | table:risk_event_log | tikv_task:{time:9ms, loops:3}                                                                                                                             | range:[100,+inf], keep order:true | N/A     | N/A  |
+-----------------------------+---------+---------+-----------+----------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------+---------+------+
4 rows in set (0.09 sec)

对应的执行计划如上

https://docs.pingcap.com/zh/tidb/stable/topn-limit-push-down#topn-和-limit-下推

查看官方文档里面如果这个limit 下推的话,是不应该存在这么多的网络流量,请问这个是没有下推成功吗?如果想减少流量的话,SQL需要怎么写

【背景】 做过哪些操作

【现象】 业务和数据库现象

【问题】 当前遇到的问题

【业务影响】

【TiDB 版本】

【应用软件及版本】 v4.0.12

【附件】 相关日志及配置信息

  • TiUP Cluster Display 信息
  • TiUP CLuster Edit config 信息

监控(https://metricstool.pingcap.com/)

  • TiDB-Overview Grafana监控
  • TiDB Grafana 监控
  • TiKV Grafana 监控
  • PD Grafana 监控
  • 对应模块日志(包含问题前后 1 小时日志)

若提问为性能优化、故障排查类问题,请下载脚本运行。终端输出的打印结果,请务必全选并复制粘贴上传。

1赞

下推实际上成功了,但是范围扫的时候,给出的条件是不一样的,你可以看看:
image

把 id 最小值的条件也加上看看?

id>=100 and id<=4000 这个范围内只有100条记录,我的疑惑是既然下推了,为啥会产生那么多的流量呢?

rang: [100,+inf] 等于是全部范围了…

貌似这个条件约束没跑到位,只能追加最小条件了…

1 ID 最小值的条件? 没太懂,是添加id< xx 来避免这种情况的意思吗
2 rang: [100,+inf] 这个没有推下去是复合预期的吗

对的,是这么理解的

推下去的结果,不是我们期望的,这里说不定有bug~ 我待会找小伙伴评估一下

嗯嗯麻烦了, 我这边的需求就是想批量拉数据,这流量放大倍数太高了。
我这个只是测试环境,线上环境流量非常大,一秒钟2000行记录,导致万兆网卡跑了一半以上了,导致部分请求超时重传了

然后拉数据的时候,如果是jdbc读取的话,最好使用流式读取

使用 StreamingResult 流式获取执行结果

一般情况下,为提升执行效率,JDBC 会默认提前获取查询结果并将其保存在客户端内存中。但在查询返回超大结果集的场景中,客户端会希望数据库服务器减少向客户端一次返回的记录数,等客户端在有限内存处理完一部分后再去向服务器要下一批。

在 JDBC 中通常有以下两种处理方式:

  • 设置 FetchSizeInteger.MIN_VALUE 让客户端不缓存,客户端通过 StreamingResult 的方式从网络连接上流式读取执行结果。
  • 使用 Cursor Fetch,首先需设置 FetchSize 为正整数,且在 JDBC URL 中配置 useCursorFetch = true

TiDB 中同时支持两种方式,但更推荐使用第一种将 FetchSize 设置为 Integer.MIN_VALUE 的方式,比第二种功能实现更简单且执行效率更高。

1赞

这个我理解是指一个SQL的结果集合比较大的情况下的优化手段:grin:

有效果的,狠明显,试试~

:pleading_face: 他没办法减少我这个场景下KV 往 TiDB 节点发送的数据量吧

不能~ 嘿嘿

你增加条件是可以的~

然后小伙伴确认是 Bug了~ 目前也只能通过条件的方式来解决了~ :+1:

能确认这个在哪些版本存在吗? 我好先规避这个问题,这个SQL在我们这边用的多,很影响性能

估计就是你用的这个版本~

对了,你还没提供版本出来,我建议你用最新的试试

提供下版本号~

版本是 v4.0.12 , 我测试环境升级到 v4.0.13 也是一样的问题

最新的是5.1.0 :nerd_face:

5.1.0 有解决这个问题吗

我也不确定,你要有环境可以试试