PostgreSQL
 sql >> Cơ Sở Dữ Liệu >  >> RDS >> PostgreSQL

SQL:Khi nói đến NOT IN và NOT EQUAL TO, cái nào hiệu quả hơn và tại sao?

Trong PostgreSQL thường có một sự khác biệt khá nhỏ ở độ dài danh sách hợp lý, mặc dù IN sạch hơn nhiều về mặt khái niệm. Rất dài AND ... <> ... danh sách và NOT IN rất dài cả hai danh sách đều hoạt động kém hiệu quả, với AND tệ hơn nhiều so với NOT IN .

Trong cả hai trường hợp, nếu chúng đủ dài để bạn thậm chí hỏi câu hỏi thì thay vào đó bạn nên thực hiện kiểm tra loại trừ truy vấn phụ hoặc chống tham gia trên danh sách giá trị.

WITH excluded(item) AS (
    VALUES('item1'), ('item2'), ('item3'), ('item4'),('item5')
)
SELECT * 
FROM thetable t
WHERE NOT EXISTS(SELECT 1 FROM excluded e WHERE t.item = e.item);

hoặc:

WITH excluded(item) AS (
    VALUES('item1'), ('item2'), ('item3'), ('item4'),('item5')
)
SELECT * 
FROM thetable t
LEFT OUTER JOIN excluded e ON (t.item = e.item)
WHERE e.item IS NULL;

(Trên các phiên bản Pg hiện đại, cả hai đều sẽ tạo ra cùng một kế hoạch truy vấn).

Nếu danh sách giá trị đủ dài (nhiều chục nghìn mục) thì việc phân tích cú pháp truy vấn có thể bắt đầu có chi phí đáng kể. Tại thời điểm này, bạn nên xem xét việc tạo một TEMPORARY bảng, COPY nhập dữ liệu cần loại trừ vào đó, có thể tạo chỉ mục trên đó, sau đó sử dụng một trong các cách tiếp cận ở trên trên bảng tạm thời thay vì CTE.

Demo:

CREATE UNLOGGED TABLE exclude_test(id integer primary key);
INSERT INTO exclude_test(id) SELECT generate_series(1,50000);
CREATE TABLE exclude AS SELECT x AS item FROM generate_series(1,40000,4) x;

trong đó exclude là danh sách các giá trị cần bỏ qua.

Sau đó, tôi so sánh các cách tiếp cận sau trên cùng một dữ liệu với tất cả các kết quả tính bằng mili giây:

  • NOT IN danh sách: 3424.596
  • AND ... danh sách: 80173.823
  • VALUES dựa trên JOIN loại trừ: 20.727
  • VALUES loại trừ truy vấn con dựa trên: 20.495
  • JOIN dựa trên bảng , không có chỉ mục nào trên danh sách cũ: 25.183
  • Dựa trên bảng truy vấn con, không có chỉ mục trên danh sách cũ: 23.985

... làm cho cách tiếp cận dựa trên CTE nhanh hơn ba nghìn lần so với AND và nhanh hơn 130 lần so với NOT IN danh sách.

Mã tại đây:https://gist.github.com/ringerc/5755247 (hãy che mắt cho bạn, những người theo dõi liên kết này).

Đối với kích thước tập dữ liệu này, việc thêm chỉ mục trên danh sách loại trừ không tạo ra sự khác biệt.

Ghi chú:

  • IN danh sách được tạo bằng SELECT 'IN (' || string_agg(item::text, ',' ORDER BY item) || ')' from exclude;
  • AND danh sách được tạo bằng SELECT string_agg(item::text, ' AND item <> ') from exclude; )
  • Truy vấn con và loại trừ bảng dựa trên kết hợp rất giống nhau qua các lần chạy lặp lại.
  • Kiểm tra kế hoạch cho thấy Pg dịch NOT IN thành <> ALL

Vì vậy, ... bạn có thể thấy rằng có một rất lớn khoảng cách giữa cả hai INAND danh sách so với thực hiện một tham gia thích hợp. Điều khiến tôi ngạc nhiên là tốc độ thực hiện nó với CTE sử dụng VALUES danh sách được ... phân tích cú pháp VALUES danh sách hầu như không mất nhiều thời gian, hoạt động tương tự hoặc nhanh hơn một chút so với phương pháp tiếp cận bảng trong hầu hết các thử nghiệm.

Thật tuyệt nếu PostgreSQL có thể tự động nhận ra một IN dài một cách phi lý mệnh đề hoặc chuỗi AND tương tự điều kiện và chuyển sang một cách tiếp cận thông minh hơn như thực hiện một phép nối băm hoặc biến nó thành một nút CTE. Ngay bây giờ nó không biết làm thế nào để làm điều đó.

Xem thêm:

  • bài đăng blog hữu ích này Magnus Hagander đã viết về chủ đề này


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Gói PGLogical 1.1 cho PostgreSQL 9.6beta1

  2. PostgreSQL có thể có ràng buộc về tính duy nhất đối với các phần tử mảng không?

  3. thông tin không đầy đủ từ truy vấn trên pg_views

  4. Mẫu bảng và các phương pháp khác để lấy các bộ số ngẫu nhiên

  5. Cách kiểm tra cơ sở dữ liệu PostgreSQL