当表列相同时,EXCEPT的执行速度比JOIN快

Jos*_*den 7 sql sql-server performance join except

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

Aar*_*and 13

任何人都无法告诉你EXCEPT永远或永远不会超过同等水平OUTER JOIN.无论您如何编写意图,优化程序都将选择适当的执行计划.

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


至少满足下列条件之一EXCEPT时使用:

  1. 查询更具可读性(这几乎总是如此).
  2. 性能得到改善.

BOTH以下为真:

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

重要的是要注意,编写等效EXCEPT查询可能是一个挑战,因为它JOIN变得更复杂和/或您依赖于部分列中的重复但不依赖于其他列.写一个NOT EXISTS等价物,虽然可读性稍差,但EXCEPT应该更容易实现 - 而且往往会导致一个更好的计划(但请注意我永远不会说ALWAYS或者NEVER,除了我刚刚做的方式).

在这篇博客文章中,我展示了至少一个案例,其中EXCEPT既有正确构造LEFT OUTER JOIN,也有同等NOT EXISTS变化.

  • @njk我删除了我的答案,因为它太普遍了...在我跑的测试中,`除了`稍快一点......但是说它通常会更快是不准确的.Aaron的答案更好,因为它解决了需要考虑的其他因素,而不是总是试图使用`except` ... (3认同)

小智 5

在以下示例中,速度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
);
Run Code Online (Sandbox Code Playgroud)

记录数:

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)
Run Code Online (Sandbox Code Playgroud)

查询使用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
Run Code Online (Sandbox Code Playgroud)

LEFT JOIN使用表进行查询,由子查询返回。

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
Run Code Online (Sandbox Code Playgroud)