Является ли динамическая хранимая процедура sql плохой вещью для большого количества записей?

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


person Xaisoft    schedule 25.11.2008    source источник
comment
Когда вы примете окончательное решение, сообщите нам об этом, и я обновлю свой ответ, чтобы убедиться, что методы/устранение неполадок, которые мы обсуждали и которые сработали, ясны.   -  person Cade Roux    schedule 25.11.2008


Ответы (10)


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

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

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

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

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

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

person Cade Roux    schedule 25.11.2008
comment
Динамический запрос в хранимой процедуре, по-видимому, на самом деле выполняется быстрее, чем нединамический запрос в хранимой процедуре. План выполнения для обоих выглядит одинаковым. - person Xaisoft; 25.11.2008
comment
Использует ли он какие-либо индексы? Каковы ваши критерии определения медлительности - по сравнению с чем? - person Cade Roux; 25.11.2008
comment
Да, все, что имеет столбцы, к которым я присоединяюсь, имеет индексы. Я просто запускаю статический процесс и динамический процесс в ssms и проверяю время, которое потребовалось для возврата всех результатов (23 секунды для динамического и 45 секунд для статического) - person Xaisoft; 25.11.2008
comment
Без более подробной информации о схемах таблиц (и количестве возвращаемых записей — помните, что всем им может потребоваться пройти по проводам, если ваш запрос вытягивает их) и индексах, будет трудно сказать. Вы выполнили запрос через анализатор настройки индекса? - person Cade Roux; 25.11.2008
comment
Еще не статика. У меня с динамическим запросом, но он не дает никаких оптимизаций. Если бы я запустил его со статическим запросом, и он дал бы предложения, повлияет ли их применение на динамический запрос? - person Xaisoft; 25.11.2008
comment
Да, динамический запрос (EXEC (@sql)) вероятно не будет проанализирован, если вы не проанализировали файл рабочей нагрузки. - person Cade Roux; 25.11.2008
comment
Когда у вас есть поисковый запрос по нескольким объединенным таблицам, столбцы с индексами должны быть столбцами поиска, а также столбцами первичного ключа/внешнего ключа, но это зависит от кардинальности различных таблиц. Анализатор настройки должен показать это. - person Cade Roux; 25.11.2008

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

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

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

person Logicalmind    schedule 25.11.2008

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

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

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

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

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

person Community    schedule 25.11.2008

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

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

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

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

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

person Will Hartung    schedule 25.11.2008

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

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

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

person HLGEM    schedule 25.11.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)
person kͩeͣmͮpͥ ͩ    schedule 25.11.2008
comment
Все параметры являются необязательными. Как это помогает в оптимизации? - person Xaisoft; 25.11.2008

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

person Chris Porter    schedule 25.11.2008

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

WHERE col2 = @col2 AND col1 = @col1

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

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

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

person Charles Graham    schedule 25.11.2008

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

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
person Jeremy    schedule 21.10.2009
comment
На какой вопрос ты отвечаешь? - person Dave; 21.10.2009
comment
Я использую это, чтобы исключить динамический sql и использовать 2 плана запросов на уровне операторов. Как уже упоминалось, выполнение AND (@EarliestDate is Null OR PublishedDate ‹ @EarliestDate) может привести к путанице SQL Server и создать неоптимальный план. Использование объединения может помочь SQL выбрать подходящий план для каждого условия без использования OPTION(RECOMPILE). - person Jeremy; 24.11.2009

Если вы пытаетесь оптимизировать до диапазона ниже 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 использует параметры или повторяется, то результаты компиляции могут кэшироваться в соответствии с: см. планы кэширования запросов что сократит время компиляции. Было бы интересно узнать, как долго живут записи в кеше, размер, совместное использование между сеансами и т. д.

person crokusek    schedule 13.12.2011