要查找两个数据库之间的所有更改,我将加入 pk 上的表并使用 date_modified 字段来选择最新记录。EXCEPT
由于表具有相同的架构,因此将使用提高性能。我想用 a 重写它EXCEPT
,但我不确定 for 的实现是否会在每种情况下EXCEPT
都执行 a 。JOIN
希望有人对何时使用有更技术性的解释EXCEPT
。
问问题
9434 次
2 回答
14
任何人都无法告诉您,它EXCEPT
总是或永远不会胜过同类产品OUTER JOIN
。无论您如何编写意图,优化器都会选择适当的执行计划。
也就是说,这是我的指导方针:
EXCEPT
当以下至少一项为真时使用:
- 查询更具可读性(这几乎总是正确的)。
- 性能得到改善。
以下两个都是真的:
- 该查询产生语义相同的结果,您可以通过充分的回归测试来证明这一点,包括所有边缘情况。
- 性能不会降低(同样,在所有边缘情况下,以及环境变化,例如清除缓冲池、更新统计信息、清除计划缓存和重新启动服务)。
重要的是要注意,编写等效EXCEPT
查询可能是一个挑战,因为它JOIN
变得更加复杂和/或您依赖于部分列而不是其他列中的重复项。写一个NOT EXISTS
等价的,虽然可读性比EXCEPT
完成起来要简单得多 - 而且通常会导致更好的计划(但请注意,我永远不会说ALWAYS
or NEVER
,除非我刚才那样做)。
在这篇博文中,我展示了至少一个案例,其中EXCEPT
一个被正确构造LEFT OUTER JOIN
的,当然还有一个等效的NOT EXISTS
变体所胜过。
于 2013-02-04T18:39:01.817 回答
3
在以下示例中,LEFT JOIN
速度比EXCEPT
70 %
(PostgreSQL 9.4.3)快
例子:
有三张桌子。suppliers
, parts
, shipments
. 我们需要得到不是伦敦任何供应商提供的所有零件。
数据库(在所有涉及的列上都有索引):
CREATE TABLE suppliers (
id bigint primary key,
city character varying NOT NULL
);
CREATE TABLE parts (
id bigint primary key,
name character varying NOT NULL,
);
CREATE TABLE shipments (
id bigint primary key,
supplier_id bigint NOT NULL,
part_id bigint NOT NULL
);
记录数:
db=# SELECT COUNT(*) FROM suppliers;
count
---------
1281280
(1 row)
db=# SELECT COUNT(*) FROM parts;
count
---------
1280000
(1 row)
db=# SELECT COUNT(*) FROM shipments;
count
---------
1760161
(1 row)
使用 查询EXCEPT
。
SELECT parts.*
FROM parts
EXCEPT
SELECT parts.*
FROM parts
LEFT JOIN shipments
ON (parts.id = shipments.part_id)
LEFT JOIN suppliers
ON (shipments.supplier_id = suppliers.id)
WHERE suppliers.city = 'London'
;
-- Execution time: 3327.728 ms
使用LEFT JOIN
with 表查询,由子查询返回。
SELECT parts.*
FROM parts
LEFT JOIN (
SELECT parts.id
FROM parts
LEFT JOIN shipments
ON (parts.id = shipments.part_id)
LEFT JOIN suppliers
ON (shipments.supplier_id = suppliers.id)
WHERE suppliers.city = 'London'
) AS subquery_tbl
ON (parts.id = subquery_tbl.id)
WHERE subquery_tbl.id IS NULL
;
-- Execution time: 1136.393 ms
于 2017-01-04T09:14:50.447 回答