2013-06-07 6 views
0

У меня есть две таблицы, которые мне нужно объединить, первая таблица содержит номер CustomerNumber и IdentificationNumber и IdentificationType. Вторая таблица содержит IdentificationType, EffectiveDate и EndDate.Есть ли более эффективный способ сделать это соединение?

Мои запросы в основном выглядит следующим образом:

Select CustomerNumber, IdentificationNumber 
From Identification i 
Inner Join IdentificationType it On it.IdentificationType = i.IdentificationType 
And it.EffectiveDate < @TodaysDate 
And (it.EndDate IS NULL Or it.EndDate > @TodaysDate) 

Мой план выполнения показывает кластерный индекс сканирование таблицы типа идентификации, я предполагаю, что это из-ИЛИ в пункте присоединения.

Есть ли более эффективный способ соединения, ЗНАЧИТЕЛЬНО, что поле EndDate ДОЛЖНО разрешить Null или реальное значение datetime?

+1

Какая версия SQL Server? – ErikE

+0

Не могли бы вы показать план выполнения, пожалуйста? –

+0

Извините, SQL Server 2008R2 – ganders

ответ

2

Я знаю, что вы сказали, что EndDate столбец должен позволить NULL, так только для записи: самый эффективный способ прекратить использование NULL сек вместо «без даты окончания» в IdentificationType таблицы, и вместо этого использовать 9999-12-31. Тогда ваши запросы могут пропустить всю статью OR. (Я понимаю, что для этого могут потребоваться некоторые изменения в приложении, но, на мой взгляд, это было бы полезно для этой причины , а именно: причина - и я видел, что этот шаблон «NULL = открытый конец» затрудняет выполнение запросов или повторяется снова и снова . моя работа и в вопросах SQL онлайн)

Кроме того, вы могли бы рассмотреть изменения порядка двух OR условиях - это может звучать как вуду, но я считаю, я слышал, что есть какие-то особые случаи, когда он может оптимизируйте лучше, когда переменная будет первой в этом конкретном сценарии (хотя я могу ошибаться).

А пока вы попробуете это и расскажете, насколько хорошо он работает по сравнению с вашими и другими решениями?

SELECT 
    CustomerNumber, IdentificationNumber 
FROM 
    dbo.Identification i 
    INNER JOIN dbo.IdentificationType it 
     ON it.IdentificationType = i.IdentificationType 
WHERE 
    it.EffectiveDate < @TodaysDate 
    AND it.EndDate IS NULL 
UNION ALL 
SELECT 
    CustomerNumber, IdentificationNumber 
FROM 
    dbo.Identification i 
    INNER JOIN dbo.IdentificationType it 
     ON it.IdentificationType = i.IdentificationType 
WHERE 
    it.EffectiveDate < @TodaysDate 
    AND it.EndDate > @TodaysDate 
; 

я поправилась от плохой работы с OR пунктами, используя эту точную стратегию. Вроде бы больно взорвать размер запроса/сложность, но возможность получить только несколько запросов полностью стоит того, что вы скачали сейчас.

В ваших сравнениях неравенства есть что-то подозрительное: первый должен иметь знак равенства в нем <=. Вы не указали нам тип данных столбцов даты и @TodaysDate, но лучше всего разработать систему, чтобы она не прерывалась для любого ввода. Поэтому, даже если переменная datetime и EffectiveDate не имеет временной части, она должна быть <= при таком сравнении, поэтому запрос точно в полночь не преминет включить данные за этот день.

P.S. Извините, что не сохраняю форматирование. Я просто понимаю запросы лучше, когда отформатирован в моем предпочтительном стиле. Кроме того, я переместил условия даты в пункт WHERE, потому что, по моему мнению, они не являются частью JOIN.

+0

Я могу попытаться реализовать этот подход, но вам придется сделать массивный поиск на нашей базе кода для поиска всех столбцов «EndDate» и реализовать значение по умолчанию (DateTime.MaxValue), если ничего не передано. Я начну искать, как это будет сложно. – ganders

+0

Еще раз спасибо Эрик. FYI - все наши столбцы даты имеют формат DateTime, а также переменную @TodaysDate. Я работаю над настройкой этой хранимой процедуры, а также рассматриваю эту систему в целом. – ganders

+1

Я настоятельно рекомендую вам провести некоторое тестирование на выполнение всех доступных вам методов (мои ответы и другие). Это должно выявить определенные аспекты, которые вам сейчас неясно. – ErikE

-1

Попробуйте использовать isnull вместо инструкции OR. Я также думаю, что вы должны использовать Datediff вместо оператора сравнения.

select CustomerNumber, IdentificationNumber 
From Identification i 
Inner Join IdentificationType it On it.IdentificationType = i.IdentificationType 
And it.EffectiveDate < @TodaysDate 
And (isnull(it.EndDate,@TodaysDate) >= @TodaysDate) 
+0

Мне любопытно, почему люди проголосовали за этот ответ. Выполняет ли запрос не очень хорошо, используя функцию ISNULL? Это ЗВУК, как хороший ответ для меня, без каких-либо испытаний ... – ganders

+0

Во-первых, обратите внимание на изменение '>' на '> =', которое изменяет 'EndDate' как * включительно * вместо * exclusive *: this не выражает те же логические условия, что и в вопросе. Если вы выполняете тестирование производительности, вы можете поделиться результатами с нами. – ErikE

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