Время ожидания запроса SQL Server в зависимости от пункта «Где»

У меня есть запрос, который использует 3 функции и несколько разных представлений под ним, которые слишком сложны, чтобы публиковать их здесь. Странная вещь, которую я испытываю, заключается в том, что при выполнении запроса верхнего уровня наличие более 1 ключа поиска приводит к тому, что запрос занимает около часа, а разделение запроса на две части занимает около 5 секунд на запрос.

Вот запрос верхнего уровня:

Select * 
from  dbo.vwSimpleInvoice i 
inner join dbo.vwRPTInvoiceLineItemDetail d on i.InvoiceID = d.InvoiceID 

Когда я добавляю это предложение where:

Where i.InvoiceID = 109581

Выполнение запроса занимает около 3 секунд. Точно так же, когда я добавляю это предложение where:

Where i.InvoiceID = 109582

это занимает около 3 секунд.

Когда я добавляю это предложение where:

Where i.InvoiceID in (109581, 109582)

Мне пришлось убить запрос примерно через 50 минут, и он никогда не возвращает никаких результатов.

Это происходит на сервере удаленного клиента под управлением SQL Server 2008 R2 Express. Когда я запускаю его локально (также на SQL Server 2008 R2 Express), я не получаю большой задержки, последнее предложение where занимает около 30 секунд для возврата. Однако у клиента гораздо больше данных, чем у меня.

Любая идея, с чего начать устранение неполадок?

Редактировать:

После комментариев ниже я перестроил индексы и статистику, что улучшило производительность первых двух предложений where, но не повлияло на третье. Затем я поиграл с запросом и обнаружил, что если переписать его так:

Select * 
from  dbo.vwSimpleInvoice i 
inner join  
    (Select * from dbo.vwRPTInvoiceLineItemDetail) d on i.InvoiceID = d.InvoiceID 
Where i.InvoiceID in (109581, 109582)

Производительность возвращается к ожидаемому уровню примерно через 200 мс. Я теперь более озадачен, чем когда-либо, относительно того, что происходит...

Редактировать 2:

На самом деле, я ошибаюсь. Это не было переписыванием запроса, я случайно изменил предложение Where во время перезаписи на:

Where d.InvoiceID in (109581, 109582)

(Изменено i на d).

Все еще в недоумении, почему это имеет такое огромное значение для внутреннего соединения?


Дальнейшее редактирование:

Играя с этим еще дальше, я все еще не могу этого понять.

Select InvoiceId from tblInvoice Where CustomerID = 2000

возвращает:

80442, 4988, 98497, 102483, 102484, 107958, 127063, 168444, 168531, 173382, 173487, 173633, 174013, 174160, 174240, 175389

Select * from dbo.vwRPTInvoiceLineItemDetail
Where InvoiceID in 
(80442, 4988, 98497, 102483, 102484, 107958, 127063, 168444, 168531, 173382, 173487, 173633, 174013, 174160, 174240, 175389)

Прогоны: 31 строка возвращена за 110 мс.

Select * from dbo.vwRPTInvoiceLineItemDetail
Where InvoiceID in 
(Select InvoiceId from tblInvoice Where CustomerID = 2000)

Прогоны: 31 строка возвращена за 65 минут.


person Molloch    schedule 11.09.2012    source источник
comment
Как выглядит план выполнения?   -  person DJ Quimby    schedule 11.09.2012
comment
Вы пытались изменить этот оператор IN на OR? Скажите, где d.InvoiceID=109581 ИЛИ d.InvoiceID=109582. Может измениться план выполнения! Но реальный способ получить помощь — опубликовать план выполнения одного идентификатора по сравнению с двумя идентификаторами в WHERE, чтобы другие могли проанализировать разницу и понять, почему это так.   -  person Joe Pineda    schedule 11.09.2012
comment
Пришлось переписывать запрос с нуля. Мне не удалось выделить ничего, что вызывало указанное выше поведение. Исходный запрос по-прежнему ведет себя так, я переписываю все дерево, чтобы избежать соединения в конце. Спасибо за помощь.   -  person Molloch    schedule 26.03.2013
comment
Является ли InvoiceID varchar или INT в обеих таблицах?   -  person Clark Vera    schedule 31.07.2018


Ответы (1)


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

Это обычное явление, которое часто усугубляется устаревшей статистикой и/или сильно фрагментированными индексами.

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

exec sp_msforeachtable "DBCC DBREINDEX('?')"
go

exec sp_msforeachtable "UPDATE STATISTICS ? WITH FULLSCAN, COLUMNS"
go

Это каноническая ссылка: Медленно в приложении, быстро в SSMS?

Если проблема не устранена после перестроения индексов и обновления статистики, у вас есть несколько вариантов:

  1. Используйте динамический SQL (но сначала прочтите это: Проклятие и благословения динамического SQL)

  2. Используйте OPTIMIZE FOR

  3. Используйте WITH(RECOMPILE)

person Mitch Wheat    schedule 11.09.2012
comment
Хорошо, перестроил все индексы и статистику, проверил предполагаемый план выполнения и фактический план для одного InvoiceID и скорректировал один индекс, как было предложено. Каждое выполнение InvoiceID сократилось примерно до 48 мс, что является значительным улучшением. Но последнее предложение where все еще работает, пока я не нажму кнопку «Стоп», в то время это заняло около 20 минут. Спасибо за вашу помощь, какие-либо дополнительные предложения? - person Molloch; 11.09.2012
comment
Не уверен, что вы получите уведомление, но только что отредактировал мой вопрос, попробовав ваши предложения. Есть идеи? Спасибо еще раз. - person Molloch; 11.09.2012