Является ли динамическая SQL-процедура плохой вещью для большого количества записей? - PullRequest
7 голосов
/ 25 ноября 2008

У меня есть таблица с почти 800 000 записей, и в настоящее время я использую динамический sql для генерации запроса на серверной части. Внешний интерфейс - это страница поиска, которая принимает около 20 параметров и в зависимости от того, был ли выбран параметр, добавляет базовый запрос «И ...». Мне любопытно, если динамический sql правильный путь (не похоже, потому что он работает медленно). Я обдумываю только создание денормализованной таблицы со всеми моими данными. Это хорошая идея, или я должен просто собрать запрос все вместе вместо того, чтобы строить его по частям, используя динамический sql. И последнее, есть ли способ ускорить динамический sql?

Ответы [ 10 ]

10 голосов
/ 25 ноября 2008

Более вероятно, что ваша индексация (или ее отсутствие) вызывает медлительность, чем динамический SQL.

Как выглядит план выполнения? Является ли тот же запрос медленным при выполнении в SSMS? Как насчет того, когда он находится в хранимой процедуре?

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

Еще не статичный. У меня с динамическим запросом, но он не дает никаких оптимизаций. Если бы я запустил его со статическим запросом, и он дал предложения, повлияет ли их применение на динамический запрос? - Xaisoft (41 мин. Назад)

Да, динамический запрос (EXEC (@sql)), вероятно, не будет анализироваться, если вы не проанализировали файл рабочей нагрузки. - Кейд Ру (33 минуты назад)

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

5 голосов
/ 25 ноября 2008

Я просто хотел бы отметить, что если вы используете этот стиль дополнительных параметров:

AND (@EarliestDate is Null OR PublishedDate < @EarliestDate)

Оптимизатор запросов не будет знать, присутствует ли этот параметр или нет при создании плана запроса. Я видел случаи, когда оптимизатор делает неправильный выбор в этих случаях. Лучшим решением является создание SQL, который использует только те параметры, которые вам нужны. Оптимизатор составит наиболее эффективный план выполнения в этих случаях. Обязательно используйте параметризованные запросы, чтобы их можно было повторно использовать в кэше планов.

4 голосов
/ 25 ноября 2008

Как и в предыдущем ответе, проверьте ваши индексы и план.

Вопрос в том, используете ли вы хранимую процедуру. Это не очевидно из того, как вы это сформулировали. Хранимая процедура создает план запроса при запуске и сохраняет этот план до его перекомпиляции. С изменяющимся SQL вы можете застрять с плохим планом запроса. Вы можете сделать несколько вещей:

1) Добавить WITH RECOMPILE в определение SP, что приведет к созданию нового плана при каждом выполнении. Это включает в себя некоторые накладные расходы, которые могут быть приемлемыми.

2) Используйте отдельные SP, в зависимости от предоставленных параметров. Это позволит лучше кэшировать план запросов

3) Использовать сгенерированный клиентом SQL. Это создаст план запроса каждый раз. Если вы используете параметризованные запросы, это может позволить вам использовать кэшированные планы запросов.

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

Не фанат динамического SQL, но если вы застряли с ним, вам, вероятно, следует прочитать эту статью: http://www.sommarskog.se/dynamic_sql.html Он действительно углубляется в лучшие способы использования динамического SQL и возможности его использования.

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

Могут быть более эффективные способы создания динамического SQL, но без кода трудно сказать. Я бы хотя бы посмотрел, использует ли он подзапросы, и заменил бы их производными объединениями таблиц. Также любой динамический SQl, использующий курсор, должен быть медленным.

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

Единственная разница между «динамическим» и «статическим» SQL - это фаза разбора / оптимизации. Как только это будет сделано, запрос будет выполняться идентично.

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

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

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

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

2 голосов
/ 25 ноября 2008

Если параметры являются необязательными, часто используется хитрость для создания процедуры, подобной этой:

CREATE PROCEDURE GetArticlesByAuthor (
    @AuthorId int,
    @EarliestDate datetime = Null )
AS
   SELECT  * --not in production code!
   FROM Articles
   WHERE AuthorId = @AuthorId
   AND (@EarliestDate is Null OR PublishedDate < @EarliestDate)
1 голос
/ 25 ноября 2008

Как уже отмечалось, если вы делаете массивный запрос, индексы являются первым узким местом, на которое нужно обратить внимание. Убедитесь, что столбцы с большими запросами проиндексированы. Также убедитесь, что ваш запрос проверяет все проиндексированные параметры, прежде чем проверяет неиндексированные параметры. Это гарантирует, что результаты сначала фильтруются с использованием индексов, а затем выполняет медленный линейный поиск, только если это необходимо. Поэтому, если col2 проиндексирован, а col1 нет, он должен выглядеть следующим образом:

WHERE col2 = @col2 AND col1 = @col1

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

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

Мне нравится Ответ Дэйва Кемпа выше.

1 голос
/ 25 ноября 2008

Здесь есть несколько хороших примеров запросов с необязательными критериями поиска: Как создать хранимую процедуру, которая будет необязательно искать столбцы?

0 голосов
/ 13 декабря 2011

Если вы пытаетесь оптимизировать до уровня ниже 1 с, может быть важно приблизительно оценить, сколько времени занимает анализ и компиляция динамического sql относительно фактического времени выполнения запроса:

 SET STATISTICS TIME ON;

, а затем выполните динамическую строку SQL «статически» и откройте вкладку «Сообщения». Я был удивлен этими результатами для динамического sql-запроса ~ 10 строк, который возвращает две строки из таблицы строк 1M:

 SQL Server parse and compile time: 
    CPU time = 199 ms, elapsed time = 199 ms.

 (2 row(s) affected)

 SQL Server Execution Times:
     CPU time = 0 ms,  elapsed time = 4 ms.

Оптимизация индекса, несомненно, сильно сдвинет барьер в 199 мс (за исключением, возможно, из-за некоторого анализа / оптимизации, включенного во время компиляции).

Однако, если динамический SQL использует параметры или повторяется, результаты компиляции могут быть кэшированы в соответствии с: См. Планы запросов кэширования , которые исключают время компиляции. Было бы интересно узнать, как долго хранятся записи в кеш-памяти, их размер, общий доступ к сеансам и т. Д.

0 голосов
/ 21 октября 2009

У меня был некоторый успех (в ограниченном количестве экземпляров) со следующей логикой:

CREATE PROCEDURE GetArticlesByAuthor (    
    @AuthorId int,    
    @EarliestDate datetime = Null 
    ) AS   

SELECT SomeColumn
FROM Articles   
WHERE AuthorId = @AuthorId   
AND @EarliestDate is Null
UNION
SELECT SomeColumn
FROM Articles   
WHERE AuthorId = @AuthorId   
AND PublishedDate < @EarliestDate
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...