Bất cứ ý tưởng tại sao IF EXISTS
sẽ làm cho nó chạy lâu hơn và đọc nhiều hơn nữa? Tôi cũng thay đổi câu lệnh chọn để làm SELECT TOP 1 [dlc].[id]
và tôi đã giết nó sau 2 phút.
Như tôi đã giải thích trong câu trả lời của mình cho câu hỏi liên quan này:
TOP (và tại sao) tác động lên kế hoạch thực hiện như thế nào?
Sử dụng EXISTS
giới thiệu một mục tiêu hàng, trong đó trình tối ưu hóa tạo ra một kế hoạch thực hiện nhằm xác định vị trí hàng đầu tiên một cách nhanh chóng. Khi làm điều này, nó giả định rằng dữ liệu được phân phối đồng đều. Ví dụ: nếu số liệu thống kê cho thấy có 100 trận đấu dự kiến trong 100.000 hàng, nó sẽ cho rằng nó sẽ chỉ phải đọc 1.000 hàng để tìm trận đấu đầu tiên.
Điều này sẽ dẫn đến thời gian thực hiện lâu hơn dự kiến nếu giả định này hóa ra là bị lỗi. Ví dụ: nếu SQL Server chọn phương thức truy cập (ví dụ: quét không có thứ tự) xảy ra để xác định giá trị khớp đầu tiên rất muộn trong tìm kiếm, thì nó có thể dẫn đến việc quét gần như hoàn tất. Mặt khác, nếu tìm thấy một hàng phù hợp trong số một vài hàng đầu tiên, hiệu suất sẽ rất tốt. Đây là rủi ro cơ bản với các mục tiêu hàng - hiệu suất không nhất quán.
Để khắc phục tạm thời, tôi đã thay đổi nó để đếm (*) và gán giá trị đó cho một biến
Thông thường có thể định dạng lại truy vấn sao cho mục tiêu hàng không được chỉ định. Không có mục tiêu hàng, truy vấn vẫn có thể kết thúc khi gặp hàng phù hợp đầu tiên (nếu được viết chính xác), nhưng chiến lược kế hoạch thực hiện có thể sẽ khác (và hy vọng, hiệu quả hơn). Rõ ràng, tính (*) sẽ yêu cầu đọc tất cả các hàng, vì vậy nó không phải là một sự thay thế hoàn hảo.
Nếu bạn đang chạy SQL Server 2008 R2 trở lên, bạn cũng có thể thường sử dụng cờ theo dõi được tài liệu và được hỗ trợ 4138 để có kế hoạch thực hiện mà không có mục tiêu hàng. Cờ này cũng có thể được chỉ định bằng cách sử dụng gợi ý được hỗ trợ OPTION (QUERYTRACEON 4138)
, mặc dù lưu ý rằng nó yêu cầu quyền sysadmin thời gian chạy , trừ khi được sử dụng với hướng dẫn kế hoạch.
không may
Không có điều nào ở trên là chức năng với một IF EXISTS
tuyên bố có điều kiện. Nó chỉ áp dụng cho DML thông thường. Nó sẽ hoạt động với SELECT TOP (1)
công thức thay thế mà bạn đã thử. Điều đó có thể tốt hơn so với việc sử dụng COUNT(*)
, phải tính tất cả các hàng đủ điều kiện, như đã đề cập trước đó.
Điều đó nói rằng, có bất kỳ cách nào để thể hiện yêu cầu này sẽ cho phép bạn tránh hoặc kiểm soát mục tiêu hàng, trong khi chấm dứt tìm kiếm sớm. Một ví dụ cuối cùng:
DECLARE @Exists bit;
SELECT @Exists =
CASE
WHEN EXISTS
(
SELECT [dlc].[ID]
FROM TableDLC [dlc]
JOIN TableD [d]
ON [d].[ID] = [dlc].[ID]
JOIN TableC [c]
ON [c].[ID] = [d].[ID2]
WHERE [c].[Name] <> [dlc].[Name]
)
THEN CONVERT(bit, 1)
ELSE CONVERT(bit, 0)
END
OPTION (QUERYTRACEON 4138);
IF @Exists = 1
BEGIN
...
END;
IF NOT EXISTS (...) BEGIN END ELSE BEGIN <do something> END
.