2010-04-29 4 views
1

Представьте себе, что у нас есть две таблицы следующим образом:SQL Server РЕГИСТРИРУЙТЕСЬ с дополнительными значениями NULL

Trades 
(
    TradeRef INT NOT NULL, 
    TradeStatus INT NOT NULL, 
    Broker INT NOT NULL, 
    Country VARCHAR(3) NOT NULL 
) 

CTMBroker 
(
    Broker INT NOT NULL, 
    Country VARCHAR(3) NULL 
) 

(Они были упрощены для целей данного примера). Теперь, если мы хотим, чтобы присоединиться к этим две таблицы по колонке Broker и если страна существует в таблице CTMBroker по стране, мы имеем следующие два варианта:

SELECT T.TradeRef,T.TradeStatus 
FROM Trades AS T 
JOIN CTMBroker AS B ON B.Broker=T.Broker AND ISNULL(B.Country, T.Country) = T.Country 

или

SELECT T.TradeRef,T.TradeStatus 
FROM Trades AS T 
JOIN CTMBroker AS B ON B.Broker=T.Broker AND (B.COUNTRY=T.Country OR B.Country IS NULL) 

Они оба логически эквивалентны, однако в этом конкретном случае для нашей базы данных (SQL Server 2008, SP1) для этих двух запросов создаются два разных плана выполнения, причем вторая версия значительно превосходит первую версию с точки зрения как времени, так и логического считывания ,

Мой вопрос в самом деле заключается в следующем: как правило, было бы предпочтительнее (1), или это просто произойдет с использованием некоторой конкретной идиосинкразии оптимизатора в SP1 2008 года (это может поэтому измениться с будущим версии SQL Server).

ответ

2

Я думаю, что причина в том, что ISNULL является функцией, поэтому SQL не может использовать какие-либо индексы в таблице, но должен сканировать таблицу, оценивая каждую строку. По этой причине я стараюсь избегать функций в условиях соединения.

+0

+1 Вы никогда не хотите использовать какую-либо функцию или выражение на «левой» стороне условия WHERE. Это не позволяет использовать индексы, и это вызывает полное сканирование таблицы - в QA, включите демонстрационный план, и вы его легко увидите; если вы видите сканирование таблиц где угодно - ничего хорошего, если только это очень маленькая таблица – IMHO

1

Не могли бы вы попробовать и это?

SELECT T.TradeRef,T.TradeStatus 
FROM Trades AS T 
JOIN CTMBroker AS B ON B.Broker=T.Broker AND B.COUNTRY=T.Country 
UNION ALL 
SELECT T.TradeRef,T.TradeStatus 
FROM Trades AS T 
JOIN CTMBroker AS B ON B.Broker=T.Broker AND B.Country IS NULL 

Часто UNION ALL превосходит OR, в зависимости от способности оптимизатора оптимизировать ИЛИ. Если это такая же скорость, как и в вашем втором запросе, это объясняет, почему это так быстро: оптимизатор может видеть, что есть два отдельных условия и использовать индекс соответствующим образом.

В первом случае, поскольку вы используете функцию не sargable (ISNULL), индекс не может быть использован.

+0

Версия UNION ALL выполняется наравне со второй из двух версий, которые я опубликовал (слабее хуже, но только из-за нескольких дополнительных логических чтений против таблицы Trades) - с точки зрения времени выполнения пара мс разница между ними). В качестве общего решения я не уверен, что UNION ALL всегда является ответом. По мере увеличения количества объединений мы фактически должны дублировать некоторый код, уменьшающий ремонтопригодность. Конечно, как вы указываете, UNION ALL, безусловно, имеет свое место в некоторых ситуациях. –

Смежные вопросы