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

KHÔNG CÓ VÀ KHÔNG TỒN TẠI

Tôi luôn mặc định là NOT EXISTS .

Các kế hoạch thực thi có thể giống nhau tại thời điểm này nhưng nếu một trong hai cột được thay đổi trong tương lai để cho phép NULLNOT IN phiên bản sẽ cần thực hiện nhiều công việc hơn (ngay cả khi không có NULL s thực sự hiện diện trong dữ liệu) và ngữ nghĩa của NOT IN if NULL s are Dù sao thì hiện tại cũng không phải là thứ bạn muốn.

Khi cả Products.ProductID hoặc [Order Details].ProductID cho phép NULLNOT IN sẽ được xử lý giống hệt với truy vấn sau.

SELECT ProductID,
       ProductName
FROM   Products p
WHERE  NOT EXISTS (SELECT *
                   FROM   [Order Details] od
                   WHERE  p.ProductId = od.ProductId) 

Kế hoạch chính xác có thể khác nhau nhưng đối với dữ liệu ví dụ của tôi, tôi nhận được như sau.

Một quan niệm sai lầm phổ biến hợp lý dường như là các truy vấn con có tương quan luôn "xấu" so với các phép nối. Chúng chắc chắn có thể xảy ra khi chúng buộc một kế hoạch vòng lặp lồng nhau (truy vấn phụ được đánh giá theo từng hàng) nhưng kế hoạch này bao gồm một toán tử logic chống bán nối. Các phép nối bán chống không bị giới hạn đối với các vòng lồng nhau nhưng cũng có thể sử dụng các phép nối băm hoặc hợp nhất (như trong ví dụ này).

/*Not valid syntax but better reflects the plan*/ 
SELECT p.ProductID,
       p.ProductName
FROM   Products p
       LEFT ANTI SEMI JOIN [Order Details] od
         ON p.ProductId = od.ProductId 

Nếu [Order Details].ProductIDNULL -able truy vấn sau đó trở thành

SELECT ProductID,
       ProductName
FROM   Products p
WHERE  NOT EXISTS (SELECT *
                   FROM   [Order Details] od
                   WHERE  p.ProductId = od.ProductId)
       AND NOT EXISTS (SELECT *
                       FROM   [Order Details]
                       WHERE  ProductId IS NULL) 

Lý do cho điều này là ngữ nghĩa chính xác nếu [Order Details] chứa bất kỳ NULL nào ProductId s là không trả về kết quả. Xem thêm phần tham gia chống bán và ống đếm hàng để xác minh điều này được thêm vào kế hoạch.

If Products.ProductID cũng được thay đổi để trở thành NULL -able truy vấn sau đó trở thành

SELECT ProductID,
       ProductName
FROM   Products p
WHERE  NOT EXISTS (SELECT *
                   FROM   [Order Details] od
                   WHERE  p.ProductId = od.ProductId)
       AND NOT EXISTS (SELECT *
                       FROM   [Order Details]
                       WHERE  ProductId IS NULL)
       AND NOT EXISTS (SELECT *
                       FROM   (SELECT TOP 1 *
                               FROM   [Order Details]) S
                       WHERE  p.ProductID IS NULL) 

Lý do cho điều đó là vì NULL Products.ProductId sẽ không được trả lại trong kết quả ngoại trừ nếu NOT IN truy vấn phụ hoàn toàn không trả về kết quả (tức là [Order Details] bảng trống). Trong trường hợp đó nó nên. Trong kế hoạch cho dữ liệu mẫu của tôi, điều này được thực hiện bằng cách thêm một kết nối chống bán khác như bên dưới.

Hiệu quả của việc này được thể hiện trong bài đăng trên blog đã được Buckley liên kết. Trong ví dụ, số lần đọc logic tăng từ khoảng 400 lên 500.000.

Ngoài ra, thực tế là một NULL có thể giảm số lượng hàng xuống 0 làm cho việc ước tính số lượng hàng rất khó khăn. Nếu SQL Server giả định rằng điều này sẽ xảy ra nhưng thực tế không có NULL các hàng trong dữ liệu phần còn lại của kế hoạch thực thi có thể tồi tệ hơn một cách thảm khốc, nếu đây chỉ là một phần của truy vấn lớn hơn, với các vòng lặp lồng nhau không thích hợp gây ra việc thực thi lặp lại một cây con đắt tiền chẳng hạn.

Đây không phải là kế hoạch thực thi khả thi duy nhất cho NOT IN trên NULL cột -able tuy nhiên. Bài viết này hiển thị một bài viết khác cho truy vấn đối với AdventureWorks2008 cơ sở dữ liệu.

Đối với NOT IN trên NOT NULL hoặc cột NOT EXISTS chống lại cột nullable hoặc không nullable, nó đưa ra kế hoạch sau.

Khi cột thay đổi thành NULL -able NOT IN kế hoạch bây giờ trông giống như

Nó bổ sung thêm một toán tử tham gia bên trong vào kế hoạch. Bộ máy này được giải thích ở đây. Đó là tất cả để chuyển đổi tìm kiếm chỉ mục tương quan đơn lẻ trước đó trên Sales.SalesOrderDetail.ProductID = <correlated_product_id> đến hai tìm kiếm trên mỗi hàng bên ngoài. Phần bổ sung nằm trên WHERE Sales.SalesOrderDetail.ProductID IS NULL .

Vì điều này nằm trong một phép nối chống bán nếu cái đó trả về bất kỳ hàng nào thì lần tìm kiếm thứ hai sẽ không xảy ra. Tuy nhiên nếu Sales.SalesOrderDetail không chứa bất kỳ NULL nào ProductID s nó sẽ tăng gấp đôi số hoạt động tìm kiếm được yêu cầu.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Chuyển đổi cột Ngày giờ từ UTC sang giờ địa phương trong câu lệnh chọn

  2. Làm cách nào để chỉnh sửa bảng để bật CASCADE DELETE?

  3. Cách sử dụng tham số với LIKE trong Sql Server Compact Edition

  4. Bảng lịch cho Kho dữ liệu

  5. Độ bền bị trễ trong SQL Server 2014