在同一表上具有多个联接的Oracle复杂查询

时间:2018-08-10 16:45:36

标签: sql oracle query-optimization sql-tuning

我正在处理Oracle 11上的庞然大物查询(约800行),并且占用了昂贵的资源。

这里的主要问题是一个约有1800万行的表mouvement,我在该表上有30个左联接。

LEFT JOIN mouvement mracct_ad1 
    ON mracct_ad1.code_portefeuille = t.code_portefeuille
    AND mracct_ad1.statut_ligne = 'PROPRE'
    AND substr(mracct_ad1.code_valeur,1,4) = 'MRAC'
    AND mracct_ad1.code_transaction = t.code_transaction
LEFT JOIN mouvement mracct_zias 
    ON mracct_zias.code_portefeuille = t.code_portefeuille
    AND mracct_zias.statut_ligne = 'PROPRE'
    AND substr(mracct_zias.code_valeur,1,4) = 'PRAC'
    AND mracct_zias.code_transaction = t.code_transaction
LEFT JOIN mouvement mracct_zixs 
    ON mracct_zias.code_portefeuille = t.code_portefeuille
    AND mracct_zias.statut_ligne = 'XROPRE'
    AND substr(mracct_zias.code_valeur,1,4) = 'MRAT'
    AND mracct_zias.code_transaction = t.code_transaction

是否有某种方法可以摆脱左联接(工会联接或示例),以使查询更快,消耗更少?执行计划之类的?

2 个答案:

答案 0 :(得分:2)

只是有关性能的注释。通常,您想“改写”以下条件:

AND substr(mracct_ad1.code_valeur,1,4) = 'MRAC'

简单来说,等式左侧的表达式将阻止索引的最佳使用,并且可能会将SQL优化器推向一个不太理想的计划。数据库引擎最终将完成比实际需要更多的工作,并且查询将慢得多。在极端情况下,他们甚至可以决定使用全表扫描。在这种情况下,您可以将其改写为:

AND mracct_ad1.code_valeur like 'MRAC%'

或:

AND mracct_ad1.code_valeur >= 'MRAC' AND mracct_ad1.code_valeur < 'MRAD'

答案 1 :(得分:0)

我猜是这样。您的代码示例没有多大意义,但您可以进行条件聚合:

left join
(select m.code_portefeuille, m.code_transaction,
        max(case when m.statut_ligne = 'PROPRE' and m.code_valeur like 'MRAC%' then ? end) as ad1,
        max(case when m.statut_ligne = 'PROPRE' and m.code_valeur like 'MRAC%' then ? end) as zia,
        . . .  -- for all the rest of the joins as well
 from mouvement m
 group by m.code_portefeuille, m.code_transaction
) m
on m.code_portefeuille = t.code_portefeuille and m.code_transaction = t.code_transaction 

您可能可以将所有30个联接替换为对汇总表的单个联接。