2013-02-04 28 views
7

Để tìm tất cả các thay đổi giữa hai cơ sở dữ liệu, tôi không tham gia các bảng trên pk và sử dụng trường date_modified để chọn bản ghi mới nhất. Việc sử dụng EXCEPT sẽ tăng hiệu suất vì các bảng có cùng một lược đồ. Tôi muốn viết lại nó với số EXCEPT, nhưng tôi không chắc liệu việc triển khai cho EXCEPT có thể thực hiện JOIN trong mọi trường hợp hay không. Hy vọng rằng ai đó có giải thích kỹ thuật hơn về thời điểm sử dụng EXCEPT.EXCEPT có thực hiện nhanh hơn JOIN khi các cột trong bảng giống nhau

+0

Bạn có cần so sánh tất cả các cột không? Hoặc, có một cột id duy nhất có thể được sử dụng để tham gia không? –

+0

Nhớ lại rằng việc triển khai cơ sở dữ liệu của các truy vấn không thực sự ánh xạ từ 1 đến 1 cho các từ khóa SQL. Có thể nhiều hơn các cấu trúc tương đương ngữ nghĩa sẽ dịch sang cùng một kế hoạch truy vấn. – millimoose

+0

@GordonLinoff Tôi cần phải so sánh tất cả các cột để cập nhật bất kỳ thay đổi nào. Và tôi đang sử dụng khóa chính để tham gia. –

Trả lời

13

Không có cách nào bất cứ ai có thể cho bạn biết rằng EXCEPT sẽ luôn luôn hoặc không bao giờ thực hiện tương đương OUTER JOIN. Trình tối ưu hóa sẽ chọn một kế hoạch thực hiện phù hợp bất kể bạn viết ý định của mình như thế nào.

Điều đó nói rằng, đây là phương châm của tôi:


Sử dụng EXCEPT khi ít nhất một những điều sau đây là đúng:

  1. Truy vấn là dễ đọc hơn (điều này sẽ hầu như luôn thật).
  2. Hiệu suất được cải thiện.

CẢ những điều sau đây là đúng:

  1. Truy vấn tạo ra kết quả giống hệt nhau về mặt ngữ nghĩa, và bạn có thể chứng minh điều này thông qua thử nghiệm hồi quy đầy đủ, bao gồm tất cả các trường hợp cạnh.
  2. Hiệu suất không bị suy thoái (một lần nữa, trong tất cả các trường hợp cạnh, cũng như thay đổi môi trường như dọn dẹp vùng đệm, cập nhật số liệu thống kê, xóa bộ đệm kế hoạch và khởi động lại dịch vụ).

Điều quan trọng cần lưu ý rằng nó có thể là một thách thức để viết một EXCEPT truy vấn tương đương như JOIN trở nên phức tạp hơn và/hoặc bạn đang dựa vào bản sao một phần của các cột nhưng không phải người khác. Viết số NOT EXISTS tương đương, trong khi ít có thể đọc được hơn EXCEPT sẽ khó hơn nhiều - và thường dẫn đến kế hoạch tốt hơn (nhưng lưu ý rằng tôi sẽ không bao giờ nói ALWAYS hoặc NEVER, ngoại trừ cách tôi vừa làm).

In this blog post I demonstrate at least one case where EXCEPT is outperformed by both a properly constructed LEFT OUTER JOIN and of course by an equivalent NOT EXISTS variation.

+0

Câu trả lời khác dường như nói với OP rằng 'EXCEPT' là * nhanh hơn *. Và nó đã biến mất. – Kermit

+0

@njk yep và tôi đã liên kết với một ví dụ ngược lại. Một lần nữa, nếu OP tìm kiếm 'ALWAYS/NEVER', anh ta sẽ không tìm thấy nó. –

+1

Tôi ngưỡng mộ sáng chói của bạn. – Kermit

2

Trong ví dụ sau, LEFT JOIN nhanh hơn EXCEPT bởi 70% (PostgreSQL 9.4.3)

Ví dụ:

Có ba bảng. suppliers, parts, shipments. Chúng tôi cần nhận tất cả các bộ phận không được cung cấp bởi bất kỳ nhà cung cấp nào ở Luân Đôn.

Cơ sở dữ liệu (có chỉ số trên tất cả các cột có liên quan):

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 
); 

ghi đếm:

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) 

Query sử dụng 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 

Truy vấn sử dụng LEFT JOIN bằng bảng, được truy vấn con trả về.

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 
Các vấn đề liên quan