Почему мой оператор SQL выполняется в N раз дольше, когда я задаю значение в качестве переменной? - PullRequest
5 голосов
/ 23 декабря 2010

Первое, что я хотел бы сказать, - это не совсем то, чего я пытаюсь достичь. Я набрал этот запрос ОЧЕНЬ МНОГО, чтобы прояснить мой вопрос.

У меня есть некластеризованный индекс для таблицы (CallDetail) на два значения, TermDate (int) и SourceSystemID (int). Чтобы быть полным, я включу точное определение индекса здесь:

CREATE NONCLUSTERED INDEX [CallDetail_TermDateSourceSystemID] ON [dbo].[CallDetail] 
(
    [TermDate] ASC,
    [SourceSystemID] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]

Проблема, с которой я сталкиваюсь, заключается в том, что когда я запускаю два почти идентичных запроса к этой таблице, я не получаю одинаковые результаты (не путать с набором результатов). Первый запрос выполняется менее чем за одну секунду и возвращает около 10000 строк. Второй запрос, когда он выполняется, продолжает выполняться до тех пор, пока я не отменю его примерно через 30 минут.

Запрос 1 (~ 1 секунда):

SELECT
    *
FROM
    CallDetail
WHERE
    CallDetail.TermDate >= 1101221 AND
    SourceSystemID = 1

Запрос 2 (> 30 минут):

DECLARE @TermDate AS INT
SET @TermDate = 1101221

SELECT
    *
FROM
    CallDetail
WHERE
    CallDetail.TermDate >= @TermDate AND
    SourceSystemID = 1

Что-то, что я хотел бы отметить, это то, что план выполнения запроса говорит мне «включить» все столбцы этой таблицы в индекс. Я считаю, что это совершенно неправильно. Я также хотел бы отметить, что если я выберу только TermDate и SourceSystemID вместо *, то получу результаты примерно через 1 секунду.

Есть ли причина, по которой при использовании переменной вместо жесткого кодирования значения туда, где оно занимает намного больше времени? Я полностью озадачен этим, и любая помощь будет очень признательна.

Спасибо!

Кристофер Хоус

Ответы [ 3 ]

5 голосов
/ 23 декабря 2010

ОК, я воспроизвел ситуацию с моим запросом:

declare @a as int
set @a = 12972100
select * from MyTable where (MyColumn > @a)

После прочтения поста marc_s я сделал следующее:

declare @a as int
set @a = 12972100
select * from MyTable where (MyColumn > @a) option (recompile)

И все снова было быстро!

2 голосов
/ 23 декабря 2010

Скорее всего, вы страдаете от прослушивания параметров и здесь .

Можете ли вы сравнить планы запросов для обоих запросов? Тот с фиксированным значением против того с параметром? Они дают вам тот же фактический план выполнения?

Только не забудьте выполнить надлежащую "очистку" и выполнить DBCC FREEPROCCACHE между запусками, чтобы эти два не влияли друг на друга ...

1 голос
/ 23 декабря 2010

UPDATE

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

Я видел, что более сложные запросы, которые содержат приведение или преобразование, имеют похожие проблемы - это одна из тех вещей, которые вы ошарашили?

Или, может быть, это «Параметр нюхает», как предлагает Марк.


Оригинальный ответ

Это потому, что необходимо привести каждое значение в таблице столбцов к типу int (столбец TermDate должен быть чем-то другим.)

В первом запросе оптимизатор умен и знает, что может привести константу к типу столбца, и делает это.

Кроме того, он не может использовать индекс, когда должен приводить для каждой строки.

Изменить эту строку

 DECLARE @TermDate AS INT

К тому же типу, что и колонка, и вы будете счастливы.

...