Почему SQL Server работает медленно при использовании переменных? - PullRequest
18 голосов
/ 24 ноября 2008

У меня есть SQL-запрос, который выполняется очень быстро, около одной секунды, когда не используются переменные, например:

WHERE id BETWEEN 5461094 and 5461097

Но когда у меня есть:

declare @firstId int
declare @lastId int

set @firstId = 5461094
set @lastId = 5461097

...
    WHERE id BETWEEN @firstId and @lastId

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

Ответы [ 7 ]

24 голосов
/ 24 ноября 2008

ОК,

  1. Вы - оптимизатор, а план запросов - это транспортное средство.
  2. Я дам вам запрос, и вы должны выбрать транспортное средство.
  3. Все книги в библиотеке имеют порядковый номер

Мой запрос: иди в библиотеку и принеси мне все книги от 3 до 5

.

Вы бы выбрали велосипед правильно, быстро, дешево, эффективно и достаточно большой, чтобы взять с собой 3 книги.

Новый запрос.

Пойдите в библиотеку и возьмите все книги между @x и @ y.

Выберите автомобиль.

Вперед.

Вот что происходит. Вы выбираете самосвал на случай, если я попрошу книги между 1 и Максвалю? Это излишне, если х = 3 и у = 5. SQL должен выбрать план, прежде чем он увидит цифры.

11 голосов
/ 24 ноября 2008

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

если диапазон всегда мал, вы можете использовать индексную подсказку, чтобы помочь этому.

3 голосов
/ 24 ноября 2008

Если эти переменные являются входными переменными для хранимого процесса, вы можете столкнуться с проблемой перехвата параметров. http://omnibuzz -sql.blogspot.com / 2006/11 / параметр обнюхивать-запасенной procedures.html

3 голосов
/ 24 ноября 2008

Забавно, что этот код тоже будет быстрым:

DECLARE @sql VARCHAR(8000)

SET @sql = 'SELECT * FROM table_x WHERE id BETWEEN ' + CAST(@firstId AS VARCHAR) + ' AND ' + CAST(@lastId AS VARCHAR)

EXEC (@sql)

(MSSQL 2000)

1 голос
/ 18 декабря 2008

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

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

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

0 голосов
/ 22 июля 2009

На самом деле, ответ был очень хорошим, я просто пишу здесь обходной путь, как он работал для меня:

Создание хранимой процедуры с помощью SQL

WHERE id BETWEEN @firstId and @lastId

После этого вызовите сохраненный процесс с параметрами @firstId и @lastId, и он ускорится. Я до сих пор не 100%, почему это работает, но это работает.

0 голосов
/ 24 ноября 2008

Идентификатор в индексе (например, первичный ключ)? Если нет, попробуйте добавить один.

Другое дело, что в первом (быстром) случае запрос выполняется немного по-другому. Чаще всего случается, что соединения выполняются в неэффективном порядке. Попробуйте переупорядочить объединения или преобразовать некоторые в подзапросы. Если вы отправите больше вашего запроса, мы поможем вам.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...