查找不同匹配记录的最快方法

时间:2013-04-11 05:04:10

标签: sql sql-server oracle rdbms

我有两个表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:)

以下是基于贾斯汀答案的查询执行计划

enter image description here

5 个答案:

答案 0 :(得分: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;

答案 1 :(得分:1)

我有答案。

在此处查看 fiddle

我使用了以下代码:

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

答案 2 :(得分:1)

查询:

<强> SQLFIDDLEExample

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 |

答案 3 :(得分: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只有一个count..over,所以你说你有大量数据,我认为这会快一点。

答案 4 :(得分:0)

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