3

我有两个表 A 和 B。两者都具有相同的结构。我们找到这两者之间的匹配记录。这是脚本

CREATE TABLE HRS.A
(
F_1 NUMBER(5,0),
F_2 NUMBER(5,0),
F_3 NUMBER(5,0)
);

CREATE TABLE HRS.B
(
F_1 NUMBER(5,0),
F_2 NUMBER(5,0),
F_3 NUMBER(5,0)
);

INSERT INTO hrs.a VALUES (1,1000,2000);
INSERT INTO hrs.a VALUES (2,1100,8000);
INSERT INTO hrs.a VALUES (3,4000,3000);
INSERT INTO hrs.a VALUES (4,2000,5000);
INSERT INTO hrs.a VALUES (5,5000,3000);
INSERT INTO hrs.a VALUES (6,6000,6000);
INSERT INTO hrs.a VALUES (7,3000,7000);
INSERT INTO hrs.a VALUES (8,1100,9000);

INSERT INTO hrs.b VALUES (1,4000,2000);
INSERT INTO hrs.b VALUES (2,6000,8000);
INSERT INTO hrs.b VALUES (3,1000,3000);
INSERT INTO hrs.b VALUES (4,2000,5000);
INSERT INTO hrs.b VALUES (5,8000,3000);
INSERT INTO hrs.b VALUES (6,1100,6000);
INSERT INTO hrs.b VALUES (7,5000,7000);
INSERT INTO hrs.b VALUES (8,1000,9000);

查找匹配记录

SELECT a.F_1 A_F1, b.F_1 B_F1 FROM HRS.A, HRS.B WHERE A.F_2 = B.F_2

结果

A_F1 B_F1
3   1
6   2
1   3
4   4
8   6
2   6
5   7
1   8

现在我想分别删除两列中的重复条目,例如 1 在 A_F1 中重复(不考虑 B_F1),因此将删除第 3(1-3)行和第 8(1-8)行。现在 6 在 B_F1 中重复(与 A_F1 无关),因此将删除第 5(8-6) 行和第 6(2-6) 行。最终结果应该是

A_F1 B_F1
3   1
6   2
4   4
5   7

现在最重要的部分,这两个表每个包含 500,000 条记录。我首先找到这些匹配记录并将其插入到临时表中,然后从第一列中删除重复项,然后从第二列中删除,然后从临时表中选择所有记录。这太慢了。我怎样才能尽可能快地做到这一点?

编辑#1

我多次执行以下语句以在每个表中生成 4096 条记录

INSERT INTO hrs.a SELECT F_1 + 1, F_2 + 1, 0 FROM hrs.a;
INSERT INTO hrs.b SELECT F_1 + 1, F_2 + 1, 0 FROM hrs.b;

现在我执行了所有答案并找到了这些

Rachcha     9.11 secs   OK
techdo      1.14 secs   OK
Gentlezerg  577  msecs  WRONG RESULTS
Justin      218  msecs  OK

甚至@Justin 也花费了 37.69 秒来记录 65,536 条记录(总计 = 131,072)

等待更优化的答案,因为实际记录数为 1,000,000 :)

这是基于贾斯汀回答的查询的执行计划

在此处输入图像描述

4

5 回答 5

3

请试试:

select A_F1, B_F1 From(
  SELECT a.F_1 A_F1, b.F_1 B_F1, 
    count(*) over (partition by a.F_1 order by a.F_1) C1,
    count(*) over (partition by b.F_1 order by b.F_1) C2
  FROM HRS.A A, HRS.B B WHERE A.F_2 = B.F_2
)x 
where C1=1 and C2=1;

一个INNER JOIN代替怎么样?请检查此查询。

select A_F1, B_F1 From(
  SELECT a.F_1 A_F1, b.F_1 B_F1, 
    count(*) over (partition by a.F_1 order by a.F_1) C1,
    count(*) over (partition by b.F_1 order by b.F_1) C2
  FROM HRS.A A INNER JOIN HRS.B B ON A.F_2 = B.F_2
)x 
where C1=1 and C2=1;
于 2013-04-11T05:36:55.270 回答
1

我有答案。

在这里看到这个小提琴

我使用了以下代码:

WITH x AS (SELECT a.f_1 AS a_f_1, b.f_1 AS b_f_1
             FROM a JOIN b ON a.f_2 = b.f_2)
SELECT *
  FROM x x1
 WHERE NOT EXISTS (SELECT 1
                     FROM x x2
                    WHERE (x2.a_f_1 = x1.a_f_1
                           AND x2.b_f_1 != x1.b_f_1)
                       OR (x2.a_f_1 != x1.a_f_1
                           AND x2.b_f_1 = x1.b_f_1)
                  )
;

编辑

我曾经在SQL fiddle上跟踪在 14 毫秒内运行的代码。我删除了公用表表达式并观察到查询性能有所提高。

SELECT a1.f_1 AS a_f1, b1.f_1 AS b_f1
  FROM a a1 JOIN b b1 ON a1.f_2 = b1.f_2
 WHERE NOT EXISTS (SELECT 1
                     FROM a a2 JOIN b b2 ON a2.f_2 = b2.f_2
                    WHERE (a2.f_1 = a1.f_1
                           AND b2.f_1 != b1.f_1)
                       OR (a2.f_1 != a1.f_1
                           AND b2.f_1 = b1.f_1))
;

输出:

A_F_1   B_F_1
3           1
6           2
4           4
5           7
于 2013-04-11T05:39:45.967 回答
1

询问:

SQLFIDDLE示例

SELECT a.f_1 AS a_f_1, 
       b.f_1 AS b_f_1
FROM a JOIN b ON a.f_2 = b.f_2
WHERE 1 = (SELECT COUNT(*)
           FROM a aa JOIN b bb ON aa.f_2 = bb.f_2
           WHERE aa.f_1 = a.f_1 )
AND 1 = (SELECT COUNT(*)
           FROM a aa JOIN b bb ON aa.f_2 = bb.f_2
           WHERE bb.f_1 = b.f_1 )

结果:

| A_F_1 | B_F_1 |
-----------------
|     3 |     1 |
|     6 |     2 |
|     4 |     4 |
|     5 |     7 |
于 2013-04-11T05:49:36.257 回答
1

根据@techdo 的回答,我认为这可能会更好:

select A_F1, B_F1 From(
  SELECT a.F_1 A_F1, b.F_1 B_F1,a.F_2,
    count(*) OVER(PARTITION BY A.F_2) C
  FROM HRS.A A, HRS.B B WHERE A.F_2 = B.F_2
)x 
where C=1 ;

多行的存在是由于相同的f_2。这个SQL只有一个计数..over,所以你说你有大量数据,我认为这会快一点。

于 2013-04-11T06:06:23.463 回答
0

这些解决方案中的每一个都需要时间,最好的一个(贾斯汀)花了将近 45 分钟,甚至没有返回 200 万条记录。我最终在临时表中插入匹配记录,然后删除重复项,我发现它比使用此数据集的这些解决方案快得多。

于 2013-04-26T15:15:13.323 回答