【问题标题】:performance of a self join on oracle db在 oracle db 上执行自联接
【发布时间】:2018-01-01 13:16:15
【问题描述】:

我有这个在 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'))

【问题讨论】:

  • 不加入,从 1 个表开始计算。
  • 我有点新手,我不明白
  • 看查询执行计划
  • 如果您刚刚对表进行了批量加载或批量插入,请对表执行收集统计信息。
  • “idtariffa”字段是主键还是唯一键?

标签: oracle performance oracle11g query-optimization self-join


【解决方案1】:

没有数据量、数据倾斜、索引定义、解释计划等细节的性能调优只是猜测。

所以这里还有一些猜测:)

您的驾驶表应该是 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) 

【讨论】:

    【解决方案2】:

    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 )
    

    【讨论】:

      【解决方案3】:

      试试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'))
      

      【讨论】:

      • 如果我“解释计划”,@mehmet-sahin 查询和 ponder-stibbons 查询的成本与我的查询完全相同...mmmmm...
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-21
      • 2013-11-17
      • 2020-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多