SQL Server có được phép đánh giá A <> B
là A < B OR A > B
, ngay cả khi một trong các biểu thức là không xác định không?
Đây là một điểm gây tranh cãi và câu trả lời là "có" đủ điều kiện.
Cuộc thảo luận tốt nhất mà tôi biết đã được đưa ra để trả lời cho báo cáo lỗi Kết nối lỗi của Itzik Ben-Gan với NEWID và Biểu thức bảng , đã bị đóng vì sẽ không sửa. Kết nối đã bị loại bỏ, vì vậy liên kết có đến một kho lưu trữ web. Đáng buồn thay, rất nhiều tài liệu hữu ích đã bị mất (hoặc khó tìm hơn) bởi sự sụp đổ của Connect. Dù sao, những trích dẫn hữu ích nhất từ Jim Hogg của Microsoft là:
Điều này đánh vào cốt lõi của vấn đề - tối ưu hóa có được phép thay đổi ngữ nghĩa của chương trình không? Tức là: nếu một chương trình mang lại một số câu trả lời nhất định, nhưng chạy chậm, liệu Trình tối ưu hóa truy vấn có hợp pháp làm cho chương trình đó chạy nhanh hơn mà còn thay đổi kết quả đã cho không?
Trước khi hét lên "KHÔNG!" (thiên hướng cá nhân của tôi cũng vậy :-), hãy xem xét: tin tốt là, trong 99% trường hợp, câu trả lời là như nhau. Vì vậy, Tối ưu hóa truy vấn là một chiến thắng rõ ràng. Tin xấu là, nếu truy vấn chứa mã hiệu ứng phụ, thì các gói khác nhau thực sự có thể mang lại kết quả khác nhau. Và NEWID () là một "chức năng" có tác dụng phụ (không xác định) như vậy phơi bày sự khác biệt. [Trên thực tế, nếu bạn thử nghiệm, bạn có thể nghĩ ra những người khác - ví dụ: đánh giá ngắn hạn các mệnh đề AND: làm cho mệnh đề thứ hai ném một số chia cho số học - các tối ưu hóa khác nhau có thể thực hiện mệnh đề thứ hai TRƯỚC mệnh đề thứ nhất] Điều này phản ánh Lời giải thích của Craig, ở những nơi khác trong luồng này, SqlServer không đảm bảo khi các toán tử vô hướng được thực thi.
Vì vậy, chúng tôi có một lựa chọn: nếu chúng tôi muốn đảm bảo một hành vi nhất định với sự hiện diện của mã không xác định (tác dụng phụ) - để kết quả của THAM GIA, ví dụ, tuân theo ngữ nghĩa của việc thực hiện vòng lặp lồng nhau - thì chúng tôi có thể sử dụng TÙY CHỌN thích hợp để ép buộc hành vi đó - như UC chỉ ra. Nhưng mã kết quả sẽ chạy chậm - thực tế, đó là chi phí, gây khó khăn cho Trình tối ưu hóa truy vấn.
Tất cả những gì đã nói, chúng tôi đang di chuyển Trình tối ưu hóa truy vấn theo hướng hành vi "như mong đợi" cho NEWID () - đánh đổi hiệu suất cho "kết quả như mong đợi".
Một ví dụ về sự thay đổi hành vi trong vấn đề này theo thời gian là NULLIF hoạt động không chính xác với các hàm không xác định như RAND () . Ngoài ra còn có các trường hợp tương tự khác sử dụng ví dụ COALESCE
với một truy vấn con có thể tạo ra kết quả không mong muốn và cũng đang được giải quyết dần dần.
Jim tiếp tục:
Kết thúc vòng lặp . . . Tôi đã thảo luận câu hỏi này với nhóm Dev. Và cuối cùng chúng tôi đã quyết định không thay đổi hành vi hiện tại, vì những lý do sau:
1) Trình tối ưu hóa không đảm bảo thời gian hoặc số lần thực hiện của các hàm vô hướng. Đây là một nguyên lý lâu dài. Đó là 'sự chậm trễ' cơ bản cho phép trình tối ưu hóa đủ tự do để đạt được những cải tiến đáng kể trong việc thực hiện kế hoạch truy vấn.
2) "Hành vi một lần mỗi hàng" này không phải là vấn đề mới, mặc dù nó không được thảo luận rộng rãi. Chúng tôi bắt đầu điều chỉnh hành vi của nó trở lại trong bản phát hành Yukon. Nhưng thật khó để xác định chính xác, trong mọi trường hợp, chính xác ý nghĩa của nó! Ví dụ: nó có áp dụng cho các hàng tạm thời được tính 'trên đường' cho kết quả cuối cùng không? - trong trường hợp đó rõ ràng phụ thuộc vào kế hoạch đã chọn. Hoặc nó chỉ áp dụng cho các hàng cuối cùng sẽ xuất hiện trong kết quả hoàn thành? - có một sự đệ quy khó chịu đang diễn ra ở đây, vì tôi chắc chắn bạn sẽ đồng ý!
3) Như tôi đã đề cập trước đó, chúng tôi mặc định là "tối ưu hóa hiệu suất" - tốt cho 99% trường hợp. 1% các trường hợp có thể thay đổi kết quả khá dễ dàng để phát hiện - các 'chức năng' có hiệu lực phụ như NEWID - và dễ 'sửa chữa' (do đó, giao dịch hoàn hảo). Mặc định này để "tối ưu hóa hiệu suất" một lần nữa, được thiết lập từ lâu và được chấp nhận. (Vâng, đó không phải là lập trường được các trình biên dịch chọn cho các ngôn ngữ lập trình thông thường, nhưng cũng vậy).
Vì vậy, các khuyến nghị của chúng tôi là:
a) Tránh phụ thuộc vào ngữ nghĩa không đảm bảo về thời gian và số lần thực hiện. b) Tránh sử dụng NEWID () sâu trong các biểu thức bảng. c) Sử dụng TÙY CHỌN để buộc một hành vi cụ thể (giao dịch hoàn hảo)
Hy vọng giải thích này giúp làm rõ lý do của chúng tôi để đóng lỗi này là "sẽ không sửa".
Thật thú vị, AND NOT (s_guid = NEWID())
mang lại kế hoạch thực hiện tương tự
Đây là hậu quả của việc chuẩn hóa, xảy ra rất sớm trong quá trình biên dịch truy vấn. Cả hai biểu thức biên dịch thành chính xác cùng một dạng chuẩn hóa, do đó cùng một kế hoạch thực hiện được tạo ra.