同一条SQL,在同一个TiDB Server实例上执行,前后执行结果不一样

【 TiDB 使用环境】生产环境
【 TiDB 版本】v5.3.0
【复现路径】客户端语言:go语言,发起程序,间隔一段时间,执行下面这条SQL,前后返回的数据量不一致。
SELECT order_id,agent_tx_no,paid_amount,pay_time,recon_time FROM pay_order WHERE pay_time > ‘1718899199’ AND pay_time < ‘1718985600’ AND status = ‘3’ AND channel_id IN (‘9’,‘31’,‘122’,‘126’,‘132’,‘136’,‘179’,‘180’,‘181’,‘182’,‘183’,‘186’,‘118’,‘119’,‘229’) ORDER BY id desc;

【遇到的问题:问题现象及影响】
【资源配置】进入到 TiDB Dashboard -集群信息 (Cluster Info) -主机(Hosts) 截图此页面
【附件:截图/日志/监控】
一、表结构

二、程序运行日志、慢日志:
1、正确的数据量为 133225 条


2、错误的数据量为 501 条


三、执行计划:执行计划走的tikv节点,paytime(pay_time)索引,已排除隐式转换导致的

还能复现吗,结果错误和结果正确的执行计划文本格式拿一下呗

1、可以复现,程序一直在运行的时候,偶尔会有几条SQL执行结果集是错误的,返回501条。
2、拿这条SQL,手工在tidb上反复执行,返回结果集又是正确的
3、下面的附件是在dashbord上粘贴出来的,对应时间点错误和正确的执行计划
错误的:
error_result_explain (6.3 KB)
正确的:
normal_result_explain (5.5 KB)

1 个赞

看样子是执行计划有问题:
错误的执行计划:

正确的执行计划:

2 个赞

错误的执行计划,为什么会走TopN计算,从每个 TiKV Region 只返回一行数据给 TiDB,那岂不是丢数据了?

TOP N 不知道哪里来的 :thinking: ,拿着 dashboard 里的执行计划的 plan_degest 去 slow query 找下,看有没有,有的话把 slow query 中的信息发出来

slow query都是一样的
SELECT order_id,agent_tx_no,paid_amount,pay_time,recon_time FROM pay_order WHERE pay_time > ? AND pay_time < ? AND status = ? AND channel_id IN (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ORDER BY id desc [arguments: (“1718899199”, “1718985600”, “3”, “9”, “31”, “122”, “126”, “132”, “136”, “179”, “180”, “181”, “182”, “183”, “186”, “118”, “119”, “229”)];

slow_query.sql (3.2 KB)

去 dashboard 里查查,看看有没有可能应用执行过 sql_select_limit 相关语句,别的真的不知道了

查之前可以看下 statement summary table 记录的全不全,参考:https://docs.pingcap.com/zh/tidb/v6.5/statement-summary-tables#为-statement-summary-设定合适的大小
不全的话可临时调大,然后等一段时间复现问题后再查

应用不好保障的吧,万一框架里还有其他穿参,你应该拿同一sql去数据库窗口执行一下。

1 个赞

我建议你用ADMIN CHECK TABLE pay_order;校验一下是不是主表和索引不一致

1 个赞

没有执行过sql_select_limit语句,在程序里面会打印执行的完整SQL,异常SQL和正常SQL的digest都是一样的

拿的是同一个SQL执行的,重复执行,返回的都是正确条数

pay_order表数据量20亿左右,执行check操作会锁表吗,会消耗大量IO和CPU资源吗?

请问是如何确认没有执行过 sql_select_limit 语句的?

这个应该不是数据索引不一致问题,你看他那个执行计划,走的同一个索引

在 github 上也没搜索到类似 bug (当然有可能是搜索的关键字不对),现在怀疑还是 sql_select_limit 可能行大,建议可以开 审计日志,或者 general 日志,或者把慢 sql 阈值调整为 0 ,等到复现后将该 session 从连接上后的所有 SQL 都拿出来分析下

1、应用程序开启debug日志,将执行的SQL完整打印输出,未发现有limit参数
2、慢日志中记录的SQL,返回错误结果的SQL和正确的SQL,是一样的,sql Digest 也是一样的

应用程序切换到去查原生的MySQL pay_order表(TiDB 同步的上游),就没有出现结果集不一样的情况了

应用程序日志反正我是不认的 :rofl:,我建议还是用上边提到的方法抓下日志(注意对业务影响)
看你这个场景很简单,就是一条 SQL 结果不一样,如果你能提供一个 demo ,稳定复现此问题,可以直接在 github 上提 issue

1 个赞