hint不生效-NO_DECORRELATE()

生产环境,
sql文本:select a.perperscovlimit,
a.rate,
a.shortratecoefficient,
round(round(a.perperscovlimit * a.rate/1000, 2) * a.shortratecoefficient/100,2),
round(a.unitpremium * a.shortratecoefficient/100,2),
a.oricurpremium,
a.unitpremium,
a.*
from a,
b
where
a.actualid = b.firstid
and b.parentid in (select e.actualid
from e,
c
where c.topid = ‘3237196716494’
and c.actualid = e.actualid
and c.specid = 3653176) and a.planno = ‘01’ and a.coveragecode = ‘1055’
执行计划:


连接列都有索引,为什么不能是用b.parentid 去做关联,而是走了hash join ,尝试使用 NO_DECORRELATE() 去绑定,但是未生效,反而报错,报错信息:
NO_DECORRELATE() is inapplicable because there are no correlated columns.

看NO_DECORRELATE这个hint的意思,是要相关子查询才能用,你这不是相关子查询啊。

2 个赞

NO_DECORRELATE()不适用,因为没有相关的列。是不是这个原因?

关注中,期待高手解答。

报错信息 NO_DECORRELATE() is inapplicable because there are no correlated columns. ,表明你的查询中并没有相关子查询(correlated subquery),所以这个函数不适用于你的查询。


我看官方文档适用的情况有这种

我看这个sql 里面有个符合 in 条件的子查询

1 个赞

报错是这个意思,但是看官方对于这个hint 的说明是: NO_DECORRELATE() 提示优化器不要尝试解除指定查询块中对应子查询的关联。该 Hint 适用于包含关联列的 EXISTSINANYALLSOME 和标量子查询,即关联子查询。

将该 Hint 写在一个查询块中后,对于该子查询和其外部查询块之间的关联列,优化器将不再尝试解除关联,而是始终使用 Apply 算子来执行查询。

那这个hint 适用什么样的场景呢?

你这是不相关子查询,如果子查询中有条件=a表或者b表中的列才是相关子查询,这个就是一个in,如果你想变成相关子查询,可以把红框内容改成and exists (select 1
from e,
c
where c.topid = ‘3237196716494’
and c.actualid = e.actualid
and c.specid = 3653176
and e.actualid=b.parentid) 这样试一下

好的 我试下哈,那有没有例子是符合in 同时也可以使用 NO_DECORRELATE() 这个hint 的

上面说的不对,in也是相关子查询,改写成exists只是换了写法,还是相关子查询,我看你现在的子查询执行计划是没问题的啊,子查询中c表的过滤条件较好,优先走了c表的索引,然后和e表进行了indexjoin,最后和外层的查询走了hashjoin,倒是外面的查询也走了indexjoin,这个是不是不太合理,外面a表的过滤性一般,过滤完和b表走indexjoin还是很浪费时间,你的想法是,子查询先和b表进行hashjoin,然后在和a表join吗?哪用NO_DECORRELATE也不合适吧,如果你单纯只是像不解关联,那只能外面的表去扫子查询里面的表,这个效果也不会好吧,不然关联呢还

加个hint

/*+ INL_JOIN(b) */

试试看,其实就b表的数据量非常可怕404亿,其他其实都还好。

我的想法是想让子查询和b表进行 index_join ,然后再去和a表进行index_join,不知道加哪种hint 可以实现,如果我把原始sql 中的and a.planno = ‘01’ and a.coveragecode = ‘1055’ 这两个条件去掉,

1 个赞

我仔细看了下,我感觉你上面的思路挺正确的。

现在问题的关键是子查询执行后,有个hashagg的算子,在子查询已经被hash一次的情况下,上层使用hashjoin确实能利用一些计算结果。这可能是导致子查询和b表不能做indexjoin的原因。

所以不解除子查询关联,对子查询用apply算子,是有希望用到b表的索引的。

但NO_DECORRELATE()说没有相关的列,难道是数据类型不一致需要转换所以不能解除?

这个sql也有改进的空间,因为select后面全是a表的数据,其实b表作为一个很大的表,也只是中间关联用一下。其实应该是

selelct a.* from a
where a.planno = ‘01’ and a.coveragecode = ‘1055’
and a.actualid in (select b.firstid
from b,c,e where b.parentid =e.actualid and c.actualid = e.actualid and c.topid = ‘3237196716494’ and c.specid = 3653176)

这样逻辑上可能更清晰一些。bce这3个表的关联结果其实只要找出符合条件的b表数据,再去找a表。不清楚这样优化器是否会有好一些的执行计划。

1 个赞

这样是不是应该用这个hint , /*+ leading(c, e), inl_join(b) */

b表的parentid 数据类型和 e表的actualid 都是 decimal(19,0) ,改写后的执行计划非常简洁,

1 个赞

和之前的执行计划没有变化

猫猫这个sql改写后,执行计划应该符合你的要求了吧,先是c和b表做indexjoin,然后和b做indexhashjoin,最后和a表hashjoin

是的,改写之后的执行计划是符合的