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

Luồng có điều kiện của máy chủ SQL

Tôi sẽ viết lại bài kiểm tra thành

IF CASE
     WHEN EXISTS (SELECT ...) THEN CASE
                                   WHEN EXISTS (SELECT ...) THEN 1
                                 END
   END = 1  

Điều này đảm bảo đoản mạch như được mô tả ở đây nhưng không có nghĩa là bạn cần chọn cái rẻ nhất để đánh giá trước thay vì để nó cho người tối ưu hóa.

Trong các thử nghiệm cực kỳ hạn chế của tôi bên dưới, điều sau dường như đúng khi thử nghiệm

1. EXISTS AND EXISTS

EXISTS AND EXISTS phiên bản có vẻ có vấn đề nhất. Chuỗi này kết hợp một số bán bên ngoài tham gia. Không có trường hợp nào nó sắp xếp lại thứ tự của các bài kiểm tra để thử và làm bài rẻ hơn trước (một vấn đề được thảo luận trong nửa sau của bài đăng trên blog này). Trong IF ... phiên bản nó sẽ không tạo ra bất kỳ sự khác biệt nào nếu nó có vì nó không bị đoản mạch. Tuy nhiên, khi vị từ kết hợp này được đặt trong WHERE điều khoản kế hoạch thay đổi và nó không ngắn mạch để việc sắp xếp lại có thể có lợi.

/*All tests are testing "If False And False"*/

IF EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2)  
AND EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1)
PRINT 'Y'
/*
Table 'spt_values'. Scan count 1, logical reads 9
Table 'spt_monitor'. Scan count 1, logical reads 1
*/

IF EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1) 
AND EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2) 
PRINT 'Y'
/*
Table 'spt_monitor'. Scan count 1, logical reads 1
Table 'spt_values'. Scan count 1, logical reads 9
*/

SELECT 1
WHERE  EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2)  
AND EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1)
/*
Table 'Worktable'. Scan count 0, logical reads 0
Table 'spt_monitor'. Scan count 1, logical reads 1
*/

SELECT 1
WHERE  EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1) 
AND EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2) 
/*
Table 'Worktable'. Scan count 0, logical reads 0
Table 'spt_values'. Scan count 1, logical reads 9

*/

Các kế hoạch cho tất cả những thứ này có vẻ rất giống nhau. Lý do cho sự khác biệt về hành vi giữa SELECT 1 WHERE ... phiên bản và IF ... phiên bản dành cho điều kiện trước đây nếu điều kiện sai thì hành vi đúng là không trả về kết quả nên nó chỉ chuỗi OUTER SEMI JOINS và nếu một sai thì hàng không sẽ chuyển sang hàng tiếp theo.

Tuy nhiên, IF phiên bản luôn luôn cần trả về kết quả là 1 hoặc 0. Kế hoạch này sử dụng một cột thăm dò trong các phép nối bên ngoài của nó và đặt giá trị này thành false nếu EXISTS kiểm tra không được thông qua (thay vì chỉ đơn giản là loại bỏ hàng). Điều này có nghĩa là luôn có 1 hàng đưa vào Tham gia tiếp theo và nó luôn được thực thi.

CASE phiên bản có gói rất giống nhưng sử dụng PASSTHRU vị từ mà nó sử dụng để bỏ qua việc thực thi JOIN nếu THEN trước đó điều kiện không được đáp ứng. Tôi không chắc tại sao lại kết hợp AND s sẽ không sử dụng cùng một cách tiếp cận.

2. EXISTS OR EXISTS

EXISTS OR EXISTS phiên bản sử dụng cách nối (UNION ALL ) làm đầu vào bên trong cho phép nối bán bên ngoài. Sự sắp xếp này có nghĩa là nó có thể ngừng yêu cầu các hàng từ phía bên trong ngay sau khi hàng đầu tiên được trả lại (tức là nó có thể gây ngắn mạch hiệu quả) Tất cả 4 truy vấn đều kết thúc với cùng một kế hoạch trong đó vị từ rẻ hơn được đánh giá đầu tiên.

/*All tests are testing "If True Or True"*/

IF EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=1)  
OR EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)<>1)
PRINT 'Y'
/*
Table 'Worktable'. Scan count 0, logical reads 0
Table 'spt_monitor'. Scan count 1, logical reads 1
*/

IF EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)<>1) 
OR EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)= 1) 
PRINT 'Y'
/*
Table 'Worktable'. Scan count 0, logical reads 0
Table 'spt_monitor'. Scan count 1, logical reads 1
*/

SELECT 1
WHERE  EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)= 1)  
OR EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)<>1)
/*
Table 'Worktable'. Scan count 0, logical reads 0
Table 'spt_monitor'. Scan count 1, logical reads 1
*/

SELECT 1
WHERE  EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)<>1) 
OR EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=1) 
/*
Table 'Worktable'. Scan count 0, logical reads 0
Table 'spt_monitor'. Scan count 1, logical reads 1
*/

3. Thêm ELSE

Tôi đã xảy ra khi thử định luật De Morgan để chuyển đổi AND thành OR và xem điều đó có tạo ra sự khác biệt nào không. Chuyển đổi truy vấn đầu tiên mang lại

IF NOT ((NOT EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2)  
OR NOT EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1)))
PRINT 'Y'
ELSE
PRINT 'N'
/*
Table 'spt_monitor'. Scan count 1, logical reads 1
Table 'spt_values'. Scan count 1, logical reads 9
*/

Vì vậy, điều này vẫn không tạo ra bất kỳ sự khác biệt nào đối với hành vi đoản mạch. Tuy nhiên, nếu bạn xóa NOT và đảo ngược thứ tự của IF ... ELSE điều kiện bây giờ hiện ngắn mạch!

IF (NOT EXISTS(SELECT COUNT(*) FROM master..spt_monitor HAVING COUNT(*)=2)  
OR NOT EXISTS (SELECT COUNT(*) FROM master..spt_values HAVING COUNT(*)=1))
PRINT 'N'
ELSE
PRINT 'Y'
/*
Table 'Worktable'. Scan count 0, logical reads 0
Table 'spt_monitor'. Scan count 1, logical reads 1
*/


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. T-SQL Bỏ qua Thủ tục Đã Lưu trữ

  2. Hiểu Nhóm theo Mệnh đề trong SQL Server - Hướng dẫn SQL Server / TSQL Phần 130

  3. SQL Server trong bộ nhớ OLTP:Khái niệm cơ bản

  4. Tính năng bảo mật đám mây Spotlight - Xóa chữ viết

  5. Khôi phục sao lưu cơ sở dữ liệu SQL Server trên phiên bản thấp hơn