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

Posted

技术标签:

【中文标题】在同一个表上具有多个连接的 Oracle 复杂查询【英文标题】:Oracle complex query with multiple joins on same table 【发布时间】:2018-08-10 16:45:36 【问题描述】:

我正在处理 oracle 11 上的怪物查询(约 800 行),它占用了昂贵的资源。

这里的主要问题是一个表 mouvement 大约有 1800 万行,我在这个表上有 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

有什么方法可以让我摆脱左连接(联合连接或示例)以使查询更快并减少消耗?执行计划什么的?

【问题讨论】:

这几行代码做的事情完全一样。 请解释这两个连接之间除了移动表的别名之外还有什么不同。 对不起,我更新了代码。 【参考方案1】:

只是关于性能的说明。通常你想“改写”这样的条件:

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'

【讨论】:

第二个是有风险的,因为NLS_SORT,不是吗? @Matthew 是的,我同意你的看法。尽管第二个仍然是一个选项,但我倾向于避免它,因为在使用非典型排序规则时它可能容易出错。 虽然是个好主意,但用like 替换substr() 似乎不太可能对具有30 个左连接的查询产生明显影响。【参考方案2】:

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

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 个连接替换为聚合表的单个连接。

【讨论】:

好吧。它只是具有不同值的相同连接。 @mouadtk 。 . .不,这用单个连接替换了一堆不同的连接到聚合结果。在这一点上,我的答案更清楚了。

以上是关于在同一个表上具有多个连接的 Oracle 复杂查询的主要内容,如果未能解决你的问题,请参考以下文章

具有多个表的联结表上的 MySQL SELECT 查询

Oracle SQL 或 PLSQL 随负载扩展

具有复杂查询和相当大数据集的本地服务器上的 PostgreSQL 超时

如何在同一个表上创建具有多个连接的视图

在 oracle 中,具有多个连接的查询执行需要更多时间

同一张表上的多个连接,在一个查询中计数