如何在Oracle中建立一个高效的UNION?

时间:2012-12-13 10:38:00

标签: performance oracle union

我正在使用Oracle 11g。

我有2个相关的表:存储值(A)和要插入的新值(B)。它们之间都是相关的,ID为3列(客户端,组和人员代码)。每个表都有大约20个其他列(让我们称之为属性)。

我必须匹配它们以便我知道哪些值是新的(B中的id而不是A中的ID)所以我将它们插入A中,它们是等于(B中的id和具有相同属性的A中),它们是不是新值(A中的ID而不是B中的ID),所以我从存储的值(A)中删除它们。

例如:

A:

client  | group | personcode    | name | surname
_________________________________________________
1       | 1     | 1             | joe   | doe
1       | 1     | 2             | carl  | john
1       | 1     | 3             | john  | john

B:

client  | group | personcode    | name | surname
_________________________________________________
1       | 1     | 1             | joe   | doe
1       | 1     | 3             | john  | john
1       | 1     | 4             | mary  | con

在此示例中,person 4是new,person 2应该被删除,1和3保持不变。

所以,我需要一个返回以下结果的查询:

client  | group | personcode    | action
_________________________________________
1       | 1     | 1             | equal
1       | 1     | 2             | remove
1       | 1     | 3             | equal
1       | 1     | 4             | new

我所做的是以下查询:

   WITH 
   A AS (
    -- select from A table
   ), 
   B AS
   (
       -- select from B table
   ),     
   delete AS 
   (
    -- select from A WHERE NOT EXISTS (B.id = A.ID)
   ),       
   news AS 
   (
    -- select from B WHERE NOT EXISTS (A.id = B.ID)
   ),
   eq AS 
   (
    -- select A.* from A, B WHERE A.id = B.id AND A.attributes = B.attributes
   ) 
   select action.client, action.group, action.personcode, 'remove' from delete action
   UNION ALL
   select action.client, action.group, action.personcode, 'new' from news action
   UNION ALL
   select action.client, action.group, action.personcode, 'equal' from eq action
   ;

问题在于,虽然这3个持续时间中的每一个都选择在不到10秒的时间内运行,但是当我使用UNIONUNION ALL合并它们时,完整查询会持续大约90秒,即使删除或者新的或者相等是空的。它可能在A或B中超过3000行。

有没有办法以更好,更快的方式获得这个结果?

3 个答案:

答案 0 :(得分:4)

您可以外连接表以生成它们之间差异的日志。

select coalesce(a.id,b.id) id,
       case when a.id is null
              then 'new'
            when b.id is null
              then 'remove'
            when a.col1 = b.col1 and a.col2 = b.col2 ...
              then 'same'
            else 'different'
        end
from    a full outer join b on (a.id = b.id)

答案 1 :(得分:2)

如果表B包含您想要的数据,为什么不使用该表而不是表A中的表?创建一个同义词,指向包含正确数据的同义词并引用该词。

答案 2 :(得分:0)

好的,谢谢大家的回复。 我终于根据this blog中描述的策略,通过一些参数来传递一些参数来过滤前两个查询 整个过程现在持续30秒,如果A或B没有行,则为0(之前,它总是持续90秒)。 这个解决方案对我当前的程序影响较小。