我有一个自我连接,在oracle DB上非常慢。我已经在所有相关领域放置了索引。有人对如何提高性能有建议吗?
select count(tNew.idtariffa) CONT
from tariffe tAtt
join tariffe tNew on tAtt.idtariffa = tNew.idtariffa
where (tAtt.stato_attivo = 't')
and (tNew.stato_attivo = 'f')
and (tAtt.validity_date < tNew.validity_date)
and (tAtt.dataimport < tNew.dataimport)
and (tNew.validity_date < to_date('2017-6-26','YYYY-MM-DD'))
尝试PUSH_PRED
提示:
select /*+ NO_MERGE(tNew) PUSH_PRED(tNew) */
count(tNew.idtariffa) CONT
from tariffe tAtt
join tariffe tNew on tAtt.idtariffa = tNew.idtariffa
where (tAtt.stato_attivo = 't')
and (tNew.stato_attivo = 'f')
and (tAtt.validity_date < tNew.validity_date)
and (tAtt.dataimport < tNew.dataimport)
and (tNew.validity_date < to_date('2017-6-26','YYYY-MM-DD'))
Exists
版本值得一试:
select count(1) cont
from tariffe n
where stato_attivo = 'f'
and validity_date < date '2017-06-26'
and exists ( select null
from tariffe
where idtariffa = n.idtariffa
and stato_attivo = 't'
and validity_date < n.validity_date
and dataimport < n.dataimport )
没有数据量、数据倾斜、索引定义、解释计划等细节的性能调优只是猜测。
所以这里有更多的猜测:)
你的驱动表应该是tariffe tNew
的,因为这是你用来在结果集顶部的那个。
tNew.validity_date < to_date('2017-6-26','YYYY-MM-DD'))
现在,除非tNew.stato_attivo = 'f'
非常有选择性,否则您将检索表中所有行的一大块(取决于记录的回退距离(,因此全表扫描将是获取这些记录的最有效方法。
tariffe tAtt
上的联接是有问题的idtariffa
因为它不是唯一的列。因此,联接是一组tNew
记录与一组tAtt
记录。这些将使用 WHERE 子句中的条件在内存中筛选。
"我已经在所有相关字段上放置了索引">
单列索引在这里无济于事。您可能会从所有相关列的复合索引中获得一些乐趣:
tariffe (stato_attivo , validity_date, idtariffa, dataimport)
如果您经常运行此查询,这将值得构建。
还有其他猜测吗?子查询分解以命中主表一次。如果tariffe
有很多列,只执行一次全表扫描会加快速度。
with cte as (
select stato_attivo , validity_date, idtariffa, dataimport
from tariffe
where validity_date < to_date('2017-6-26','YYYY-MM-DD'
)
select count(tNew.idtariffa) CONT
from cte tNew
join cte tAtt on tAtt.idtariffa = tNew.idtariffa
where (tAtt.stato_attivo = 't')
and (tNew.stato_attivo = 'f')
and (tAtt.validity_date < tNew.validity_date)
and (tAtt.dataimport < tNew.dataimport)