2011-06-13 56 views
7

我试图在postgresql中的两个几乎相同的表之间得到差异。我当前运行的查询是:Postgresql UNION需要运行单个查询的时间长达10倍​​

SELECT * FROM tableA EXCEPT SELECT * FROM tableB; 

SELECT * FROM tableB EXCEPT SELECT * FROM tableA; 

上述每个查询大约需要2分钟运行(它的一大桌)

我想将两者结合起来查询希望节省时间,所以我尝试过:

SELECT * FROM tableA EXCEPT SELECT * FROM tableB 
UNION 
SELECT * FROM tableB EXCEPT SELECT * FROM tableA; 

虽然它的工作,它需要20分钟运行!我猜想最多需要4分钟时间来分别运行每个查询。

联盟正在做一些额外的工作,是否需要这么长时间?或者有什么方法可以加快速度(有或没有UNION)?

更新:使用UNION ALL运行查询需要15分钟,几乎是自己运行每个的4倍,我是否正确地说UNION(全部)不会加快速度?

+0

单个tableA或tableB中是否有重复项需要省略?否则,请尝试“联合所有”。 – 2011-06-13 23:59:44

+0

@ScrumMeister:我之前没有想过这个。联合会删除来自单个表的重复项吗?我认为它只删除了两个联合表之间的重复项。我可能不得不研究这一点。 – RThomas 2011-06-14 00:20:58

+0

你可以发布'EXPLAIN ANALYZE'的输出吗? – 2011-06-14 06:00:23

回答

11

关于您的“额外工作”问题。是。 Union不仅结合了这两个查询,而且还通过并删除了重复项。这与使用不同的陈述是一样的。

由于这个原因,特别是与你的除外声明“union all”结合起来可能会更快。

更多在这里阅读: http://www.postgresql.org/files/documentation/books/aw_pgsql/node80.html

+0

我刚刚运行“SELECT * FROM tableA EXCEPT SELECT * FROM tableB UNION ALL SELECT * FROM tableB EXCEPT SELECT * FROM tableA;”花了15分钟,所以它仍然没有分开运行两个查询那么快。 – lanrat 2011-06-14 01:03:13

+0

我选择这个作为正确的答案,但它似乎仍然分别运行查询加快了速度。 – lanrat 2011-06-14 02:22:51

+0

@RThomas通过增加union all来增加冗余值,如果我想要不同的值呢? – Lokesh 2018-01-08 06:17:04

3

除了合并第一和第二查询的结果,UNION默认情况下还会删除重复记录。 (见http://www.postgresql.org/docs/8.1/static/sql-select.html)。检查两个查询之间的重复记录涉及的额外工作可能是额外的时间。在这种情况下,不应该有任何重复的记录,因此通过指定UNION ALL可以避免寻找重复的额外工作。

SELECT * FROM tableA EXCEPT SELECT * FROM tableB 
UNION ALL 
SELECT * FROM tableB EXCEPT SELECT * FROM tableA; 
+0

似乎我得到我的答案输入有点慢。荣誉lazyDBA – dave 2011-06-14 00:23:47

-2

你可以使用表A FULL OUTER JOIN tableB的,它会给你想要的东西(用黑白配的连接条件),只有1次扫描,它可能会比上述2个查询速度更快。

请发送更多信息。

2

我不认为你的代码返回你想要的结果集。我宁愿想要这样做:

SELECT * 
    FROM (
     SELECT * FROM tableA 
     EXCEPT 
     SELECT * FROM tableB 
     ) AS T1 
UNION 
SELECT * 
    FROM (
     SELECT * FROM tableB 
     EXCEPT 
     SELECT * FROM tableA 
     ) AS T2; 

换句话说,你想要的是一组互斥成员。如果是这样,你需要在SQL关系运算符优先级读了;),当你有,你可以实现上面可以合理化到:

SELECT * FROM tableA 
UNION 
SELECT * FROM tableB 
EXCEPT 
SELECT * FROM tableA 
INTERSECT 
SELECT * FROM tableB; 

FWIW,使用子查询(派生表T1T2)明确显示(否则这将是隐含的)关系运算符的优先级,你原来的查询是这样的:

SELECT * 
    FROM (
     SELECT * 
      FROM (
       SELECT * 
        FROM tableA 
       EXCEPT 
       SELECT * 
        FROM tableB 
       ) AS T2 
     UNION 
     SELECT * 
      FROM tableB 
     ) AS T1 
EXCEPT 
SELECT * 
    FROM tableA; 

以上可以relationalised到:

SELECT * 
    FROM tableB 
EXCEPT 
SELECT * 
    FROM tableA; 

...我想不是什么意图。

+0

感谢您的解释!我运行了您提供的第一个查询,但运行这两个单独的查询所花的时间仍然很长。我正在运行的两个查询正是我想要的;我只是希望它更快:)。您提供的第二个查询花费了> 1小时,所以我停止了它(所有其他所有在10分钟以内的地方) – lanrat 2011-06-16 01:03:06

相关问题