【问题标题】:Efficient Four-Way Join in Oracle SQLOracle SQL 中的高效四路连接
【发布时间】:2015-02-15 05:01:51
【问题描述】:

我有两个要加入的表,Table1Table2。每个表都有两个唯一的键,我们称它们为 Key1Key2。我想要做的是 LEFT JOIN Table2 to Table1,其中任何键都匹配四种可能组合中的任何一种:

  • Table1.Key1 = Table2.Key1
  • Table1.Key1 = Table2.Key2
  • Table1.Key2 = Table2.Key1
  • Table1.Key2 = Table2.Key2

我的问题是:有没有有效的方法来做到这一点?现在我想出了类似的东西,但它需要很长时间才能运行。

CREATE TABLE NEW_TABLE AS
SELECT a.*,
       CASE WHEN a.Key1 = b.Key1 THEN 1 ELSE 0 END AS match1,
       CASE WHEN a.Key1 = c.Key2 THEN 1 ELSE 0 END AS match2,
       CASE WHEN a.Key2 = b.Key1 THEN 1 ELSE 0 END AS match3,
       CASE WHEN a.Key2 = c.Key2 THEN 1 ELSE 0 END AS match4
FROM Table1 a
LEFT JOIN (Select Key1 From Table2 Where Key1 is not null) b
    on a.Key1 = b.Key1 or a.Key2 = b.Key1
LEFT JOIN (Select Key2 From Table2 Where Key2 is not null) c
    on a.Key1 = c.Key2 or a.Key2 = c.Key2
;

没救了,我知道...

编辑:示例数据和所需结果如下:

表 1:

Key1     Key2     Sales    Revenue
qwer!@   dhfgfw   455      30005
asdf#$   dfg654   221      28711
edfr2#   gg%%^f   213      31667
gthy!2   awd^&5   133      13345
rf$#22   34ffgg   655      41237
bhjk%g   w3erff   122      10066
f&*yhj   dffghj   126      11004

表 2:

Key1     Key2 
qwer!@   {null}
{null}   dfg654
ffgww2   ppolkk
{null}   gthy!2
jjjj33   l00kjl
nmnmnm   34ffgg
awd^&5   {null}

期望的结果:

Key1     Key2     Sales    Revenue   match1    match2    match3    match4
qwer!@   dhfgfw   455      30005     1         0         0         0
asdf#$   dfg654   221      28711     0         0         0         1
edfr2#   gg%%^f   213      31667     0         0         0         0
gthy!2   awd^&5   133      13345     1         0         1         0
rf$#22   34ffgg   655      41237     0         0         0         1
bhjk%g   w3erff   122      10066     0         0         0         0
f&*yhj   dffghj   126      11004     0         0         0         0

【问题讨论】:

  • 您能否发布一个数据示例以及您希望达到的结果?
  • 不知道这是否真的有帮助,但如果您有任何相关索引,我建议您加入实际表而不是子查询。你这样做的方式(我认为)会让你很难使用这些表上的任何索引。

标签: sql oracle performance left-join


【解决方案1】:

连接条件中的or 可能是性能问题。我建议你改用exists

SELECT a.*,
       (case when exists (select 1 from table2 b where a.Key1 = b.Key1) then 1 else 0 end) as match1,
       (case when exists (select 1 from table2 b where a.Key1 = b.Key2) then 1 else 0 end) as match2,
       (case when exists (select 1 from table2 b where a.Key2 = b.Key1) then 1 else 0 end) as match3,
       (case when exists (select 1 from table2 b where a.Key2 = b.Key2) then 1 else 0 end) as match4
FROM Table1 a;

过滤掉NULL 并不重要,因为NULL 无论如何都会使比较失败。

为了获得最佳性能,您需要在 table2(key1)table2(key2) 上建立索引。

【讨论】:

    【解决方案2】:

    如果您只需要行的组合而不需要排列(即,如果table1.keytable2.key1table2.key2 具有相同的值,则只返回一行),那么这应该有效:

    SELECT a.*,
           CASE WHEN a.Key1 = b.Key1 THEN 1 ELSE 0 END AS match1,
           CASE WHEN a.Key1 = b.Key2 THEN 1 ELSE 0 END AS match2,
           CASE WHEN a.Key2 = b.Key1 THEN 1 ELSE 0 END AS match3,
           CASE WHEN a.Key2 = b.Key2 THEN 1 ELSE 0 END AS match4
    FROM Table1 a
    LEFT JOIN Table2 b
        on a.Key1 in (b.Key1, b.key2) or a.key2 in (b.key1, b.key2);
    

    插入提供的数据,此解决方案确实有效,但需要对其进行汇总以提供您正在寻找的结果:

    SELECT   a.key1,
             a.key2,
             a.sales,
             a.revenue,
             MAX (CASE WHEN a.key1 = b.key1 THEN 1 ELSE 0 END) AS match1,
             MAX (CASE WHEN a.key1 = b.key2 THEN 1 ELSE 0 END) AS match2,
             MAX (CASE WHEN a.key2 = b.key1 THEN 1 ELSE 0 END) AS match3,
             MAX (CASE WHEN a.key2 = b.key2 THEN 1 ELSE 0 END) AS match4
    FROM     table1 a
             LEFT JOIN table2 b
                ON a.key1 IN (b.key1, b.key2) OR a.key2 IN (b.key1, b.key2)
    GROUP BY a.key1,
             a.key2,
             a.sales,
             a.revenue;
    

    【讨论】:

    • 谢谢!我不能说我明白为什么,但是我在我的数据样本(表 1 中的 10,000 条记录和表 2 中的 100,000 条记录)上尝试了这种方法和 Gordon 的方法,而且这个方法更快(5:51.138 vs. 13: 18.075)。关于为什么这会比其他方法更快的任何想法?
    • 很大程度上取决于table2 的大小及其索引。 Gordon 的解决方案将不得不为table1 中的每一行查询table2 四次。如果它可以有效地做到这一点,那么这两个查询就不会有太大的区别了。
    猜你喜欢
    • 2017-09-13
    • 1970-01-01
    • 1970-01-01
    • 2017-02-06
    • 2017-03-22
    • 1970-01-01
    • 2012-06-23
    • 2017-02-23
    • 1970-01-01
    相关资源
    最近更新 更多