10

要查找两个数据库之间的所有更改,我将加入 pk 上的表并使用 date_modified 字段来选择最新记录。EXCEPT由于表具有相同的架构,因此将使用提高性能。我想用 a 重写它EXCEPT,但我不确定 for 的实现是否会在每种情况下EXCEPT都执行 a 。JOIN希望有人对何时使用有更技术性的解释EXCEPT

4

2 回答 2

14

任何人都无法告诉您,它EXCEPT总是或永远不会胜过同类产品OUTER JOIN。无论您如何编写意图,优化器都会选择适当的执行计划。

也就是说,这是我的指导方针:


EXCEPT以下至少一项为真时使用:

  1. 查询更具可读性(这几乎总是正确的)。
  2. 性能得到改善。

以下两个都是真的:

  1. 该查询产生语义相同的结果,您可以通过充分的回归测试来证明这一点,包括所有边缘情况。
  2. 性能不会降低(同样,在所有边缘情况下,以及环境变化,例如清除缓冲池、更新统计信息、清除计划缓存和重新启动服务)。

重要的是要注意,编写等效EXCEPT查询可能是一个挑战,因为它JOIN变得更加复杂和/或您依赖于部分列而不是其他列中的重复项。写一个NOT EXISTS等价的,虽然可读性比EXCEPT完成起来要简单得多 - 而且通常会导致更好的计划(但请注意,我永远不会说ALWAYSor NEVER,除非我刚才那样做)。

在这篇博文中,我展示了至少一个案例,其中EXCEPT一个被正确构造LEFT OUTER JOIN的,当然还有一个等效的NOT EXISTS变体所胜过。

于 2013-02-04T18:39:01.817 回答
3

在以下示例中,LEFT JOIN速度比EXCEPT70 % (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 JOINwith 表查询,由子查询返回。

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 回答