У меня есть несколько сложный запрос SQL Server 2008 (около 200 строк довольно плотного SQL), который не выполнялся так, как мне было нужно. Со временем производительность упала с примерно 0,5 секунды до примерно 2 секунд.
Взглянув на план выполнения, стало совершенно очевидно, что путем изменения порядка соединений производительность может быть улучшена. Я сделал, и это сделало ... примерно до 0,3 секунды. Теперь запрос имеет подсказку «OPTION FORCE ORDER» , и жизнь хороша.
Вместе со мной сегодня, очистка базы данных. Я архивирую около 20% строк, не предпринимая никаких действий в соответствующей базе данных, за исключением удаления строк ... план выполнения ПОЛНОСТЬЮ скрыт . Он полностью неверно оценивает, сколько строк вернут определенные поддеревья, и (например) заменяет:
<Hash>
с
<NestedLoops Optimized='false' WithUnorderedPrefetch='true'>
Теперь время запроса увеличивается примерно с 0,3 до 18 с. (!) Просто потому, что я удалил строки. Если я уберу подсказку запроса, я вернусь к времени запроса около 2 с. Лучше, но хуже.
Я воспроизвел проблему после восстановления базы данных в нескольких местах и на серверах. Простое удаление около 20% строк из каждой таблицы всегда вызывает эту проблему.
- Является ли это нормальным для порядка принудительного соединения, чтобы сделать оценки запроса полностью неточными (и, следовательно, время запроса непредсказуемым)?
- Должен ли я ожидать, что мне придется либо принять неоптимальную производительность запросов, либо наблюдать за ней как ястреб и часто вручную редактировать подсказки запросов? Или, может быть, намекает на каждое присоединение? .3 к 2 с большой удар, чтобы взять.
- Очевидно ли, почему оптимизатор взорвался после удаления строк? Например, «да, потребовалось сканирование образца, и поскольку я ранее заархивировал большинство строк в истории данных, образец дал редкие результаты, поэтому он недооценил необходимость операции сортированного хэша»?
Если вы хотите увидеть планы выполнения, пожалуйста, предложите место, где я могу их опубликовать. В противном случае, я выбрал самый потрясающий бит. Вот фундаментальная неправильная оценка, числа в скобках (предполагаемые: фактические) строки.
/ Clustered Index Scan (908:7229)
Nested Loops (Inner Join) --<
\ NonClustered Index Seek (1:7229)
Обратите внимание, что внутренний цикл должен сканировать 908 строк, но вместо этого сканирует 52 258 441. Если бы это было точно, эта ветвь работала бы около 2 мс, а не 12 с. Перед удалением строк эта оценка внутреннего соединения была отключена всего в 2 раза и выполнялась как совпадение хэша для двух кластеризованных индексов.