Будь-яка ідея, чому IF EXISTS
б змусити його працювати так довше і зробити так багато читає? Я також змінив заяву select для виконання, SELECT TOP 1 [dlc].[id]
і я вбив її через 2 хвилини.
Як я пояснив у своїй відповіді на це пов'язане питання:
Як (і чому) ТОП впливає на план виконання?
Використання EXISTS
вводить ціль рядка, де оптимізатор виробляє план виконання, спрямований на швидке розміщення першого рядка. При цьому передбачається, що дані розподіляються рівномірно. Наприклад, якщо статистика показує, що 100 очікуваних матчів у 100 000 рядків, буде припускатися, що для першого матчу доведеться прочитати лише 1000 рядків.
Це призведе до більш тривалих, ніж очікувалося, часу виконання, якщо це припущення виявиться несправним. Наприклад, якщо SQL Server обрав метод доступу (наприклад, не упорядкований сканування), який трапляється знайти перше співпадаюче значення дуже пізно в процесі пошуку, це може призвести до майже повного сканування. З іншого боку, якщо серед перших рядків знайдеться відповідна рядок, продуктивність буде дуже хорошою. Це основний ризик з цілями ряду - непослідовність виконання.
Як тимчасове виправлення я змінив його, щоб зробити підрахунок (*) і призначити це значення змінній
Зазвичай можна переформулювати запит таким чином, щоб мета рядка не була призначена. Без мети рядка запит може все-таки закінчуватися, коли зустрічається перший відповідний рядок (якщо він написаний правильно), але стратегія плану виконання може бути іншою (і, сподіваємось, більш ефективною). Очевидно, що для count (*) буде потрібно читання всіх рядків, тому це не є ідеальною альтернативою.
Якщо ви використовуєте SQL Server 2008 R2 або пізнішої версії, ви також можете використовувати документально підтверджений прапор 4138 сліду для отримання плану виконання без мети рядка. Цей прапор також можна вказати, використовуючи підтримуваний підказку OPTION (QUERYTRACEON 4138)
, хоча слід пам’ятати, що він вимагає дозволу системного адміністратора виконання , якщо він не використовується з керівництвом плану.
На жаль,
Ніщо з перерахованого вище не функціонує з IF EXISTS
умовним твердженням. Це стосується лише звичайного DML. Він буде працювати з альтернативною SELECT TOP (1)
рецептурою, яку ви спробували. Це може бути краще, ніж використання COUNT(*)
, яке повинно рахувати всі кваліфіковані рядки, як було зазначено раніше.
Однак, існує будь-яка кількість способів висловити цю вимогу, що дозволить вам уникнути або контролювати мету рядка, припиняючи пошук на ранньому терміні. Останній приклад:
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
.