【问题标题】:Oracle: How to Rewrite UNION for PerformanceOracle:如何重写 UNION 以提高性能
【发布时间】:2014-09-01 14:16:36
【问题描述】:

我有运行良好的 ORACLE UNION SQL。 你能帮我找到重写 SQL 的替代方法吗:

SELECT * 
FROM (
  select app_id, org_id, emp_id, name, name_id,
  from TableA AAA, TableC CCC, TableB BBB
  where BBB.ID=CCC.ID
  AND AAA.ID=BBB.ID
UNION
  select app_id, org_id, emp_id, name, name_id,
  from TableA AAA, TableC CCC,TableD DDD 
  where DDD.ID=CCC.ID
  AND AAA.ID=DDD.ID
) MYTABLE
WHERE MYTABLE.app_id = '1234'
AND MYTABLE.org_id = '5678';

我尝试按照一些建议将 UNION SQL 转换为标量查询,但出现错误:“值太多”

SELECT 
(select app_id, org_id, emp_id, name, name_id,
from TableA AAA, TableC CCC, TableB BBB
where BBB.ID=CCC.ID
and AAA.ID=BBB.ID
and app_id = '1234'
and org_id = '5678'
) q1,

(select app_id, org_id, emp_id, name, name_id,
from TableA AAA, TableC CCC,TableD DDD 
where DDD.ID=CCC.ID
and AAA.ID=DDD.ID
and app_id = '1234'
and org_id = '5678'
) q2
) from dual;

我的标量查询可能有什么问题? 还是有其他方法可以以更好的性能重写此查询? 非常感谢。

【问题讨论】:

  • 在这样的选择中使用子查询,列中不能有多个值。您是否尝试过在单次选择中对表 D 和 B 进行外连接?
  • 你能公开 app_id 和 org_id 来自哪些表吗?如果它们来自 AAA 和 CCC,那么您可以在连接到 BBB 和 DDD 之前将它们限制在子查询中。联合很昂贵,因为它必须过滤掉不同的值(相对于联合所有,它不在乎)。如果可以限制必须分组/排序的记录数,将对逻辑 IO 的数量产生巨大影响。
  • 如果两个查询都没有返回重复项以过滤掉,您可以使用union allunion all 将保留重复项不变,而union 基本上得到了结果的所有distinct 值,这显然是一个额外的处理步骤。

标签: php oracle stored-procedures plsql


【解决方案1】:

首先是在单个选择中进行过滤。尽早限制您正在使用的数据集。您现在正在做的是从表中获取所有行,从该大数据集中获取唯一值(您使用的是 UNION 而不是 UNION ALL),过滤记录。

  select app_id, org_id, emp_id, name, name_id,
  from TableA AAA, TableC CCC, TableB BBB
  where BBB.ID=CCC.ID
  AND AAA.ID=BBB.ID
  AND app_id = '1234'
  AND org_id = '5678'
  UNION
  select app_id, org_id, emp_id, name, name_id,
  from TableA AAA, TableC CCC,TableD DDD 
  where DDD.ID=CCC.ID
  AND AAA.ID=DDD.ID
  AND app_id = '1234'
  AND org_id = '5678';

PS 您的选择在语法上不正确。选择列表以逗号结尾。

【讨论】:

    【解决方案2】:
    SELECT app_id, org_id, emp_id, name, name_id 
    FROM 
    (
    SELECT app_id, org_id, emp_id, name, name_id
    FROM TableA AAA
    JOIN TableB BBB ON AAA.ID = BBB.ID
    JOIN TableC CCC ON BBB.ID = CCC.ID
    
    UNION
    
    SELECT app_id, org_id, emp_id, name, name_id 
    FROM TableA AAA
    JOIN TableC CCC ON AAA.ID = CCC.ID
    JOIN TableD DDD ON CCC.ID = DDD.ID 
    ) MYTABLE
    
    WHERE MYTABLE.app_id = '1234'
    AND 
    MYTABLE.org_id = '5678';
    

    【讨论】:

    • 我不明白这与原始查询有何不同,除了将连接从 where 子句移动到 ANSI 连接语法
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-31
    • 2020-07-17
    • 1970-01-01
    • 2013-01-16
    • 2014-04-25
    • 2011-01-24
    相关资源
    最近更新 更多