Để 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
Trả lời
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:
- Truy vấn là dễ đọc hơn (điều này sẽ hầu như luôn thật).
- Hiệu suất được cải thiện.
Và CẢ những điều sau đây là đúng:
- 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.
- 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).
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
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? –
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
@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. –