原sql运行正常外面包一层就很慢 (不相关子查询优化为相关子查询了?)

【 TiDB 使用环境】生产环境
【 TiDB 版本】7.4 和 7.5
【复现路径】做过哪些操作出现的问题
【遇到的问题:sql本身比较简单运行正常,但是框架会在外面包一层,就变的很慢】
如下的sql,内部的sql是一个关联多表,根据名称汇总数量的sql,这个sql运行正常;其结果只有很少几条的数据;
可是当在外面包一层查询时整个sql就非常慢。
SELECT * FROM (
SELECT sum(Q.pe_qty) qty, N.pe_name
FROM
xxx_Qty Q
INNER JOIN xxx_Name ON Q.name_id = N.name_id
WHERE XXX
GROUP BY
N.PE_NAME
) T_A_0
WHERE T_A_0.PE_NAME = ‘高XX’
;
由于内部sql运行良好,就没有贴详细的细节了;
怎么让外面包的一层不影响原来的内部sql的优化执行

补充:看执行计划,是把外层包的sql中的条件应用到内层sql,并且提前执行这个过滤了;

属于是谓词下推相关的影响吗?
看优化相关的文档只有指定让谓词下推,没有指定禁止下推的

问题明朗了:

select * from (
select sum(A.qty), D.name from
A
inner join B on xxx
inner join C on xxx
inner join D on xxx
group by D.name
)Temp
where temp.name = ‘name1’

内部有多个表关联,正常情况下优化了关联顺序是 A B C D;
当在外层带了D.name条件时,这个条件没有索引,并不高效;tidb却将关联顺序变了,先用 D.name 过滤。

请问大佬们,tidb有没有什么优化提示,让整个内部sql完全独立啊

估计外层的过滤条件下推到内层里执行了,这个可以看下具体执行计划

:thinking:这个优化逻辑是对的吧?有条件先按条件过滤减少数据量。
是不是可以加个索引?或者把where条件放到inner join的on后面试试

select /*+ NO_DECORRELATE() */ sum(A.qty) 加个hint试试?

D应该有索引

这个问题比较高级,超纲了

执行计划呢? 可以使用 USE_INDEX 指定使用某个索引

SELECT /*+ LEADING(t1, t2) */ 内部sql用这个强制下顺序试试

使用wtih table as 方式试试
with t as select sum(A.qty), D.name from
A
inner join B on xxx
inner join C on xxx
inner join D on xxx
group by D.name
select * from t where t.name = ‘name1’

这种就是方便看吧,执行计划应该还是一样

确实是这样的,下推了
由于这个字段不适合加索引,所以暂时不考虑加索引
目前解决办法是 改写sql如下:

select * from A
inner join B
inner join C
STRAIGHT_JOIN D
where xxx
强制关联顺序,不让优化器提前执行D的查询

这样修改是有效的,但是应该不是最好的

  1. 有没有更通用的方法,指定不要下推
  2. 有没有Tidb方面的大佬,跟踪下,根本问题是tidb做了一个负优化;为什么把这么低效的计划判断为 好的计划了

补充信息 A/B/C 有其他比较好的索引过滤条件了;
D表比较大; D.name 不适合建索引,至少目前不考虑。

一样的,还是会把条件下推到里面执行

正常情况下,如果D.name有索引,或者 前面的A、B、C几个表没有更好的条件,可能下推是合理的;
现在情况是A、B、C关联有很好的过滤了;D.name 没有索引;D表也比较大

:thinking:正如你说的,这可能是做了个负优化,可以去给tidb提个需求。

这个本质还是因为TiDB优化器在一些场景下的代价评估有问题导致选择了错误的执行计划,这个我们在实际中还是遇到不少,这些目前应用端能做的就是去绑定执行计划。

https://docs.pingcap.com/zh/tidb/stable/sql-plan-replayer#使用-plan-replayer-保存和恢复集群现场信息

建议提供集群现场信息。

因为没有办法复现,就没有办法修复啊。

看执行计划 + 索引提示

:muscle:这个工具不错