Là mệnh đề SQL WHERE ngắn mạch được đánh giá?


142

Các biểu thức boolean trong SQL có phải là mệnh đề ngắn mạch không?

Ví dụ:

SELECT * 
FROM Table t 
WHERE @key IS NULL OR (@key IS NOT NULL AND @key = t.Key) 

Nếu @key IS NULL ước tính là đúng, thì @key KHÔNG phải là NULL VÀ @key = t.Key được đánh giá?

Nếu không, tại sao không?

Nếu có, nó có được đảm bảo không? Đây có phải là một phần của ANSI SQL hay là cơ sở dữ liệu cụ thể?

Nếu cơ sở dữ liệu cụ thể, SqlServer? Oracle? MySQL?


Không phải mệnh đề @key KHÔNG phải là thừa? Mệnh đề @key IS NULL trên LHS có quan tâm đến điều này không?
tiêu

10
@splender - phụ thuộc vào câu trả lời cho câu hỏi
Greg Dean

@Greg: Tôi đồng ý với người chi tiêu. Tôi không thấy sự thiếu hoặc hiện diện của ngắn mạch tạo ra sự khác biệt. Nếu @key IS NULL, thì @key = t.Key sẽ luôn trả về false, vì NULL! = NULL (rốt cuộc đó là lý do tại sao chúng tôi sử dụng IS NULL).
Michael Madsen

14
@Michael và @spender - Điểm của câu hỏi là, điều kiện thứ hai có đánh giá hay không. Điểm của câu hỏi là không, câu lệnh SQL cụ thể này được viết bằng càng ít ký tự càng tốt. Trong các ví dụ phức tạp hơn, chắc chắn nó sẽ có vấn đề, vì nếu mệnh đề where ngắn mạch, bạn có thể viết các biểu thức có thể là sai.
Greg Dean

2
Đoản mạch ngụ ý đánh giá các điều kiện từ trái sang phải. Đưa ra một điều kiện như WHERE a = 1 AND b = 2nó có thể hiệu quả cho công cụ cơ sở dữ liệu để tìm tất cả các hàng trong đó b = 2 trước, sau đó lọc trong đó a = 1. Nếu bạn yêu cầu bảo đảm thì trình tối ưu hóa trở nên vô dụng.
Salman A

Câu trả lời:


72

Dự thảo ANSI SQL 2003 5WD-01-Framework-2003-09.pdf

6.3.3.3 Trình tự đánh giá quy tắc

[...]

Trong trường hợp mức độ ưu tiên không được xác định bởi các Định dạng hoặc dấu ngoặc đơn, việc đánh giá hiệu quả các biểu thức thường được thực hiện từ trái sang phải. Tuy nhiên, nó phụ thuộc vào việc triển khai cho dù các biểu thức có thực sự được đánh giá từ trái sang phải hay không, đặc biệt khi toán hạng hoặc toán tử có thể gây ra các điều kiện được nêu lên hoặc nếu kết quả của các biểu thức có thể được xác định mà không đánh giá hoàn toàn tất cả các phần của biểu thức.


4
Phụ thuộc thực hiện? Tuyệt quá. Tốt để biết, quá. Ít nhất CASElà ngắn mạch.
dakab

3
Điều này không có nghĩa là các đánh giá biểu thức không xác định? "(0 = 0 HOẶC NULL)", luôn luôn là NULL nếu tất cả các thuật ngữ được ước tính, nhưng luôn luôn đúng nếu được đánh giá từ trái sang phải và ngắn mạch.
dùng48956

6
SQL là một ngôn ngữ khai báo, về cơ bản nó thể hiện logic của tính toán mà không mô tả dòng điều khiển của nó; mà loại mâu thuẫn với phong cách bắt buộc của đánh giá ngắn mạch và hậu quả của nó.
Jorge Garcia

Tôi đã không nghĩ về nó theo cách đó @JorgeGarcia. Tôi đoán việc đánh giá ngắn mạch sẽ ngầm buộc một đơn đặt hàng cho các hoạt động. Tôi đang vật lộn với một số mã trong đó điều này có thể là gốc rễ của một vấn đề tinh tế. Cảm ơn vì sự sáng suốt.
Carnot Antonio Romero

58

Từ những điều trên, ngắn mạch là không thực sự có sẵn.

Nếu bạn cần nó, tôi đề nghị một tuyên bố Case:

Where Case when Expr1 then Expr2 else Expr3 end = desiredResult

Expr1luôn được đánh giá, nhưng chỉ một trong số Expr2Expr3sẽ được đánh giá mỗi hàng.


3
Điều đó phụ thuộc vào việc triển khai RDBMS mà tôi giả sử. Đối với SQL Server ít nhất, tồn tại ít nhất một ngoại lệ được ghi lại là không hiển thị hành vi này (tức là ngắn mạch); cf CASE (Transact-SQL) - Nhận xét . Tôi đã trích dẫn trường hợp này trong câu trả lời này, tôi đã đưa ra câu hỏi Sql - Thứ tự rõ ràng về các điều kiện WHERE? .
TT.

1
Biểu hiện trường hợp , không tuyên bố.
jarlh

19

Tôi nghĩ rằng đây là một trong những trường hợp tôi viết nó như thể nó không bị đoản mạch, vì ba lý do.

  1. Bởi vì đối với MSSQL, điều đó không được giải quyết bằng cách nhìn vào BOL ở nơi rõ ràng, vì vậy đối với tôi, điều đó làm cho nó mơ hồ về mặt kinh điển.

  2. bởi vì ít nhất thì tôi biết mã của tôi sẽ hoạt động. Và quan trọng hơn, những người đến sau tôi cũng vậy, vì vậy tôi sẽ không khiến họ phải lo lắng qua cùng một câu hỏi lặp đi lặp lại.

  3. Tôi viết thường xuyên đủ cho một số sản phẩm DBMS và tôi không muốn phải nhớ những khác biệt nếu tôi có thể làm việc xung quanh chúng một cách dễ dàng.


4
Đề nghị tuyệt vời. Nó không trả lời câu hỏi, nhưng đó là một quan điểm thực dụng tuyệt vời. vì vậy +1
Greg Dean

12

Tôi không tin rằng việc đoản mạch trong SQL Server (2005) được đảm bảo. SQL Server chạy truy vấn của bạn thông qua thuật toán tối ưu hóa có tính đến rất nhiều thứ (chỉ mục, số liệu thống kê, kích thước bảng, tài nguyên, v.v.) để đưa ra một kế hoạch thực hiện hiệu quả. Sau đánh giá này, bạn không thể nói chắc chắn rằng logic ngắn mạch của bạn được đảm bảo.

Tôi đã gặp phải câu hỏi tương tự vào lúc trước và nghiên cứu của tôi thực sự không cho tôi một câu trả lời dứt khoát. Bạn có thể viết một truy vấn nhỏ để cung cấp cho bạn cảm giác bằng chứng rằng nó hoạt động nhưng bạn có thể chắc chắn rằng khi tải trên cơ sở dữ liệu của bạn tăng lên, các bảng sẽ lớn hơn và mọi thứ được tối ưu hóa và thay đổi trong cơ sở dữ liệu, kết luận đó sẽ giữ. Do đó, tôi không thể và đã nhầm lẫn về mặt thận trọng và đã sử dụng CASE trong mệnh đề WHERE để đảm bảo đoản mạch.


7

Bạn phải ghi nhớ cách thức hoạt động của cơ sở dữ liệu. Đưa ra một truy vấn được tham số hóa, db xây dựng một kế hoạch thực hiện dựa trên truy vấn đó mà không có các giá trị cho các tham số. Truy vấn này được sử dụng mỗi khi truy vấn được chạy bất kể giá trị được cung cấp thực tế là gì. Việc truy vấn ngắn mạch với các giá trị nhất định sẽ không quan trọng đối với kế hoạch thực hiện.


6
nó quan trọng đối với tốc độ thực hiện!
dùng4951

Chỉ vì đó là cách nó hoạt động hiện tại không có nghĩa là nó không thể thay đổi. Chúng ta phải tách mô hình / ngữ nghĩa khỏi thực hiện. Các kế hoạch thực hiện được triển khai trong nội bộ để tối ưu hóa việc thực hiện các truy vấn ... và ngữ nghĩa ngắn mạch không chỉ mâu thuẫn với bản chất khai báo của SQL mà còn có thể hạn chế các tối ưu hóa đó. Tuy nhiên, nếu ngữ nghĩa đánh giá ngắn mạch được DBMS hỗ trợ, việc thực hiện các kế hoạch thực hiện sẽ thay đổi để hỗ trợ các ngữ nghĩa như vậy.
Jorge Garcia

3

Tôi thường sử dụng điều này cho các tham số tùy chọn. Đây có giống như ngắn mạch?

SELECT  [blah]
FROM    Emp
WHERE  ((@EmpID = -1) OR (@EmpID = EmpID))

Điều này cho tôi tùy chọn để vượt qua -1 hoặc bất cứ điều gì để tính đến việc kiểm tra tùy chọn một thuộc tính. Đôi khi điều này liên quan đến việc tham gia trên nhiều bảng, hoặc tốt nhất là một khung nhìn.

Rất tiện dụng, không hoàn toàn chắc chắn về công việc bổ sung mà nó mang lại cho công cụ db.


2

Đối với SQL Server, tôi nghĩ nó phụ thuộc vào phiên bản nhưng kinh nghiệm của tôi với SQL Server 2000 là nó vẫn đánh giá @key = t.Key ngay cả khi @key là null. Nói cách khác, nó không thực hiện đoản mạch hiệu quả khi đánh giá mệnh đề WHERE.

Tôi đã thấy mọi người đề xuất một cấu trúc như ví dụ của bạn như một cách thực hiện truy vấn linh hoạt nơi người dùng có thể nhập hoặc không nhập các tiêu chí khác nhau. Quan sát của tôi là Key vẫn tham gia vào kế hoạch truy vấn khi @key là null và nếu Key được lập chỉ mục thì nó không sử dụng chỉ mục một cách hiệu quả.

Loại truy vấn linh hoạt với các tiêu chí khác nhau có lẽ là một trường hợp trong đó SQL được tạo động thực sự là cách tốt nhất để đi. Nếu @key là null thì bạn hoàn toàn không bao gồm nó trong truy vấn.


2

Chỉ cần vấp phải câu hỏi này, và đã tìm thấy mục blog này: http://rusanu.com/2009/09/13/on-sql-server-boolean-operator-short-circuit/

Máy chủ SQL có thể tự do tối ưu hóa một truy vấn bất cứ nơi nào cô ấy thấy phù hợp, vì vậy trong ví dụ được đưa ra trong bài đăng trên blog, bạn không thể dựa vào việc đoản mạch.

Tuy nhiên, một CASE rõ ràng được ghi lại để đánh giá theo thứ tự bằng văn bản - kiểm tra các bình luận của bài đăng trên blog đó.


1

Đặc điểm chính của đánh giá ngắn mạch là nó dừng đánh giá biểu thức ngay khi kết quả có thể được xác định. Điều đó có nghĩa là phần còn lại của biểu thức có thể bị bỏ qua vì kết quả sẽ giống nhau bất kể nó được đánh giá hay không.

Toán tử boolean nhị phân là comutative, có nghĩa là:

a AND b == b AND a
a OR  b == b OR  a
a XOR b == b XOR a

do đó không có sự đảm bảo về thứ tự đánh giá. Thứ tự đánh giá sẽ được xác định bởi trình tối ưu hóa truy vấn.

Trong các ngôn ngữ với các đối tượng có thể có các tình huống mà bạn có thể viết các biểu thức boolean chỉ có thể được đánh giá bằng đánh giá ngắn mạch. Cấu trúc mã mẫu của bạn thường được sử dụng trong các ngôn ngữ như vậy (C #, Delphi, VB). Ví dụ:

if(someString == null | someString.Length == 0 )
  printf("no text in someString");

Ví dụ C # này sẽ gây ra ngoại lệ nếu someString == nullvì nó sẽ được đánh giá đầy đủ. Trong đánh giá ngắn mạch, nó sẽ làm việc mọi lúc.

SQL chỉ hoạt động trên các biến vô hướng (không có đối tượng) không thể chưa được khởi tạo, do đó không có cách nào để viết biểu thức boolean không thể đánh giá được. Nếu bạn có một số giá trị NULL, mọi so sánh sẽ trả về false.

Điều đó có nghĩa là trong SQL, bạn không thể viết biểu thức được đánh giá khác nhau tùy thuộc vào việc sử dụng ngắn mạch hoặc đánh giá đầy đủ.

Nếu triển khai SQL sử dụng đánh giá ngắn mạch, hy vọng nó chỉ có thể tăng tốc độ thực hiện truy vấn.


1
Yep, toán tử boolean là giao hoán. Tôi không nghĩ các đối tượng (hoặc không) có liên quan gì đến nó.
Greg Dean

1

Tôi không biết về việc lưu thông ngắn, nhưng tôi sẽ viết nó như một câu lệnh if-other

if (@key is null)
begin

     SELECT * 
     FROM Table t 

end
else
begin

     SELECT * 
     FROM Table t 
     WHERE t.Key=@key

end

Ngoài ra, các biến phải luôn luôn ở bên phải của phương trình. Điều này làm cho nó có thể mở rộng.

http://en.wikipedia.org/wiki/Sargable


1
Bất cứ ai cũng có thể chứng thực nó về các biến ở bên phải? Vì một số lý do tôi có một thời gian khó tin nó.
Greg Dean

searchoracle.techtarget.com/expert/KnowledoltaseAnswer/ từ không thể tìm thấy nhiều thứ khác ngay bây giờ
DForck42

Theo tôi hiểu bài viết. Đó là nói về các chức năng trên các tên cột không thể nói được. Mà tôi hiểu. Tuy nhiên, tôi không nghĩ (A = @a) hoặc (@a = A) có vấn đề.
Greg Dean

tôi có thể sai có thể là một câu hỏi hay nếu nó không tồn tại.
DForck42

1

Bên dưới bài kiểm tra nhanh và bẩn trên SQL Server 2008 R2:

SELECT *
FROM table
WHERE 1=0
AND (function call to complex operation)

Điều này trở lại ngay lập tức mà không có hồ sơ. Loại hành vi ngắn mạch đã có mặt.

Sau đó đã thử điều này:

SELECT *
FROM table
WHERE (a field from table) < 0
AND (function call to complex operation)

biết không có hồ sơ sẽ đáp ứng điều kiện này:

(a field from table) < 0

Điều này mất vài giây, cho thấy hành vi ngắn mạch không còn nữa và hoạt động phức tạp đang được đánh giá cho mỗi bản ghi.

Hy vọng điều này sẽ giúp các chàng trai.


1
Tôi đoán là truy vấn đầu tiên là "ngắn gọn" trong thời gian biên dịch, trước khi thực hiện kế hoạch thực sự bắt đầu.
Louis Bolog

1

Dưới đây là bản demo để chứng minh rằng MySQL thực hiện ngắn mạch mệnh đề WHERE :

http://rextester.com/GVE4880

Điều này chạy các truy vấn sau đây:

SELECT myint FROM mytable WHERE myint >= 3 OR myslowfunction('query #1', myint) = 1;
SELECT myint FROM mytable WHERE myslowfunction('query #2', myint) = 1 OR myint >= 3;

Sự khác biệt duy nhất giữa chúng là thứ tự các toán hạng trong điều kiện OR.

myslowfunctioncố tình ngủ trong một giây và có tác dụng phụ là thêm một mục vào bảng nhật ký mỗi khi nó được chạy. Dưới đây là kết quả của những gì được ghi lại khi chạy hai truy vấn trên:

myslowfunction called for query #1 with value 1
myslowfunction called for query #1 with value 2
myslowfunction called for query #2 with value 1
myslowfunction called for query #2 with value 2
myslowfunction called for query #2 with value 3
myslowfunction called for query #2 with value 4

Ở trên cho thấy một hàm chậm được thực thi nhiều lần hơn khi nó xuất hiện ở phía bên trái của một điều kiện OR khi toán hạng khác không luôn luôn đúng (do ngắn mạch).


4
Hmm những gì bạn có thể muốn nói "Đây là một bản demo để chứng minh rằng MySQL thực hiện mệnh đề WHERE ngắn mạch trong trường hợp cụ thể này :"
TT.

1
Chắc chắn - đó chỉ là một bằng chứng rằng nó có thể xảy ra.
Steve Chambers

0

Việc này mất thêm 4 giây trong trình phân tích truy vấn, do đó, từ những gì tôi có thể thấy IF thậm chí còn không được rút ngắn ...

SET @ADate = NULL

IF (@ADate IS NOT NULL)
BEGIN
    INSERT INTO #ABla VALUES (1)
        (SELECT bla from a huge view)
END

Nó sẽ là tốt đẹp để có một cách đảm bảo!


-2

Nhưng rõ ràng là máy chủ MS Sql hỗ trợ lý thuyết ngắn mạch, để cải thiện hiệu suất bằng cách tránh kiểm tra không cần thiết,

Ví dụ hỗ trợ:

SELECT 'TEST'
WHERE 1 = 'A'

SELECT 'TEST'
WHERE 1 = 1 OR 1 = 'A'

Ở đây, ví dụ đầu tiên sẽ dẫn đến lỗi 'Chuyển đổi không thành công khi chuyển đổi giá trị varchar' A 'thành kiểu dữ liệu int.'

Trong khi điều thứ hai chạy dễ dàng khi điều kiện 1 = 1 được ước tính thành TRUE và do đó điều kiện thứ hai hoàn toàn không chạy.

Hơn nữa

SELECT 'TEST'
WHERE 1 = 0 OR 1 = 'A'

ở đây điều kiện đầu tiên sẽ đánh giá là sai và do đó DBMS sẽ chuyển sang điều kiện thứ hai và một lần nữa bạn sẽ gặp lỗi chuyển đổi như trong ví dụ trên.

LƯU Ý: TÔI VIẾT ĐIỀU KIỆN R ER RÀNG CHỈ CẦN THỰC HIỆN THỜI TIẾT MỌI ĐIỀU KIỆN ĐƯỢC THỰC HIỆN HOẶC NGẮN HẠN NẾU KẾT QUẢ TRONG R ER RÀNG CÓ Ý NGH THEA ĐIỀU KIỆN ĐƯỢC THỰC HIỆN, RÚT GỌN KHÁC.

KHAI THÁC ĐƠN GIẢN

Xem xét,

WHERE 1 = 1 OR 2 = 2

vì điều kiện đầu tiên được đánh giá thành TRUE , việc đánh giá điều kiện thứ hai là vô nghĩa vì đánh giá của nó ở bất kỳ giá trị nào đều không ảnh hưởng đến kết quả, vì vậy cơ hội tốt cho Sql Server để tiết kiệm thời gian Thực hiện truy vấn bằng cách bỏ qua kiểm tra hoặc đánh giá điều kiện không cần thiết .

trong trường hợp "HOẶC" nếu điều kiện đầu tiên được ước tính thành TRUE , toàn bộ chuỗi được kết nối bởi "HOẶC" sẽ được coi là được đánh giá là đúng mà không đánh giá các điều kiện khác.

condition1 OR condition2 OR ..... OR conditionN

nếu điều kiện1 được ước tính là đúng, phần còn lại của tất cả các điều kiện cho đến khi điều kiệnN sẽ bị bỏ qua. Trong các từ tổng quát khi xác định TRUE đầu tiên , tất cả các điều kiện khác được liên kết bởi OR sẽ bị bỏ qua.

Xem xét điều kiện thứ hai

WHERE 1 = 0 AND 1 = 1

vì điều kiện đầu tiên được đánh giá là FALSE, việc đánh giá điều kiện thứ hai là vô nghĩa vì đánh giá của nó ở bất kỳ giá trị nào đều không ảnh hưởng đến kết quả, vì vậy một lần nữa cơ hội tốt để Sql Server tiết kiệm thời gian Thực hiện truy vấn bằng cách bỏ qua kiểm tra hoặc đánh giá điều kiện không cần thiết .

trong trường hợp "VÀ" nếu điều kiện đầu tiên được ước tính thành FALSE , toàn bộ chuỗi được kết nối với "VÀ" sẽ được coi là được đánh giá với FALSE mà không đánh giá người khác.

condition1 AND condition2 AND ..... conditionN

nếu điều kiện1 được ước tính thành FALSE , phần còn lại của tất cả các điều kiện cho đến khi điều kiệnN sẽ bị bỏ qua. Nói một cách khái quát khi xác định FALSE đầu tiên , tất cả các điều kiện khác được liên kết bởi AND sẽ bị bỏ qua.

SAU ĐÂY, MỘT CHƯƠNG TRÌNH TUYỆT VỜI NÊN LUÔN LUÔN CHƯƠNG TRÌNH TUYỆT VỜI TRONG NHỮNG CÁCH NÀO, BÀI GIẢNG MỞ RỘNG HOẶC ĐIỀU KIỆN HẤP DẪN NHẤT ĐƯỢC TÌM HIỂU MỘT CÁCH NÀO ĐỂ KIẾM ĐƯỢC ĐIỀU KIỆN ĐẦU TIÊN, HOẶC KIẾM ĐƯỢC ĐIỀU KIỆN


Lý do Downvote: luôn kiểm tra mọi thứ trên một máy chủ thực với dữ liệu thực tế. Có vẻ như bình luận trước đây của tôi đã ăn.
Jasmine
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.