嵌套查询,in里层有序的主键,查询出的数据没有按照主键排序

【 TiDB 使用环境】生产环境
【 TiDB 版本】v6.5.3
【复现路径】select * from t1 where id in (select id from t1 where id > 432100 order by id asc limit 4000);
【遇到的问题:问题现象及影响】

  1. select * from t1 where id in (select id from t1 where id > 432100 order by id asc limit 4000);
  2. 批量sql如上,研发代码中每次将查询的结果存放到内存中,然后取最后一条数据的id值作为最大值,给下一批次使用;
  3. 在没有升级前是5.4.3是正常的,最后一个值就是最大值,升级到6.5.3后,批量压测出现问题,经过排查发现最后一个值不是最大值了,最后导致整个业务出现重复数据;
  4. 用6.5.5这个版本去测试,发现问题不再出现,也就是说在6.5.5问题修复了;
  5. 请问6.5.3是否有什么参数可以控制这个排序?

【资源配置】进入到 TiDB Dashboard -集群信息 (Cluster Info) -主机(Hosts) 截图此页面
【附件:截图/日志/监控】

select * from t1 where id in (select id from t1 where id > 432100 order by id asc limit 4000);
经过研发打印日志发现,in子句里的值之前版本是排序的,6.5.3里会出现不排序的情况,但是手动测试没有触发这个问题,只有在并行跑批的时候会出现

这跟版本没关系吧,select * from t1 where id in (select id from t1 where id > 432100 order by t1_id asc limit 4000);你这个sql后面是不是应该再排下序就行了。select * from t1 where id in (select id from t1 where id > 432100 order by t1_id asc limit 4000) order by id asc;

是的,这样改是可以解决问题的,但是这个是批量,修改一次就要发版,压测,不知道有没有参数可以控制,之前在5.4.3还是没问题的

explain 对比一下执行计划,如果执行计划一致,那可能是个概率问题。

还真是有点区别
新版本

旧版本

这个问题不能依赖执行计划保证,比如hashindexjoin不能保证记录顺序,indexjoin应该可以。他说6.5.3有问题,应该走的hashindexjoin。但是这个问题并不是数据库的事情,还是使用的问题,可以用分页函数处理。

来自 @人如其名

补充下,index_hash_join和index_join的区别。
参考:https://github.com/pingcap/tidb/pull/8661

2 个赞
  1. select * from t1 where id in (select id from t1 where id > 432100 order by id asc limit 4000);

这个语句结果没排序,为啥会认为最后一条是最大值?

请问如何能让6.5.3这个版本也强制使用index_join

研究下hint,加index_join的hint,不过需要修改语句或者用绑定执行计划方式。没有参数直接关闭index_hash_join。另外一种是修改评估成本来左右优化器的偏好,这样就可以不动程序了,但是这个你应该搞不定,需要对tidb有较深入理解才行。

好的,多谢了

找到原因了,是代价模型的原因,参数是 tidb_cost_model_version,6.5.3使用的是2,5.4.3是1
设置为1,使用index join,排序是正确的,设置为2,使用index hash join,排序会乱
根本原因还是sql的问题,已经修改sql在外层加上order by排序

https://docs.pingcap.com/zh/tidb/v6.5/cost-model

1 个赞

写sql的有个原则,除了order by 任何语句都不保证顺序

一个待排序一个是不带排序把?

此话题已在最后回复的 60 天后被自动关闭。不再允许新回复。