执行计划distinct性能问题

【 TiDB 使用环境】 Poc
【 TiDB 版本】6.2
【遇到的问题】索引字段做distinct时走IndexFullScan
【问题现象及影响】
在做select distinct O_ORDERDATE from orders limit 10 查询时候,O_ORDERDATE 存在索引的情况下为何还要走IndexFullScan呢?
distinct问题.txt (5.1 KB)

这是正常的,非主键列上做distinct,肯定需要扫描所有数据才能聚合,所以选了indexfullscan 否则就是fulltablescan了。 agg操作已经下推到tikv了,不知道limit 下推是否支持聚合后的结果,理论上每个cop task聚合后再limit处理后再返回会更好。另外est rows和act rows差异很大,手动收集下统计信息后再跑下看看

2 个赞

这个在传统bptree上做distinct limit10,直接走索引最多十几个ms(索引叶在内存),只需要扫描少量索引页就可以获取结果。这里用的是lsmtree,tidb对二级索引实现的方式是索引字段+rowid拼接作为key,那么我想查找去重key时候不能跳跃查找么?如果不能发生了范围内的顺序索引key扫描,那么最多也是扫描出limit 10的结果后就停止吧?感觉没必要全部索引扫描啊。

rocskdb里貌似没有这种跳着扫的,都是顺序往下扫直到不符合条件的, 不知道innodb里对这种是否是按你说的处理。limit 要做agg后面执行,所以只能每个cop task做完agg后 才能Limit 10 ,不能在cop task内 limit 10,我觉得优化的点是在 tikv内对agg后的数据做limit返回, 看下面issue貌似是能支持的 https://github.com/pingcap/tidb/issues/3938 ,可能有条件限制吧。

IndexFullScan正常,“最多也是扫描出limit 10的结果后就停止”也是对的(所以会ms级别返回结果),确实不需要扫全部的结果,所以这里不正常。为什么索引叶就一定在内存?MySQL是有跳跃查找(但是是有条件的),等下我贴出来。

https://dev.mysql.com/doc/refman/8.0/en/group-by-optimization.html ,‘跳跃查找’只有在大于两个字段的group by才有意义

bptree里索引本来是去重的,所以检索很快。但是tidb这里的二级索引key都是包含rid导致大量扫描。–这里更正下,二级索引是不去重的。

我可能表达的有点问题。我是说假设索引叶都是在内存的情况下。主要是表达tidb对于索引字段distinct时候扫描更多的页面,这个我认为应该可以尽量避免的。

二级索引里记得是不去重的

是的,二级索引不去重,我弄错了。不过bptree的扫描方式用range scan 并不需要full index scan

这个就是h5n1大佬说的,因为limit没有下推,从tikv索引扫描了所有数据然后再做的limit,如果能下推limit应该就是rangescan

这个跟跳扫没有太大关系,跳扫是在带不上索引的前导列,前导列选择率很高的情况下会用到

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