SP занимает 15 минут, но тот же запрос при выполнении возвращает результаты через 1-2 минуты

Итак, в основном у меня есть эта относительно долгая хранимая процедура. Основной поток выполнения состоит в том, что он SELECTS INTO некоторые данные в таблицах temp, объявленных с помощью знака #, а затем запускает курсор через эти таблицы, генерирует "общее количество" в третью временную таблицу, которая создается с помощью CREATE. Затем эта итоговая таблица temp соединяется с другими таблицами в БД, чтобы сгенерировать результат после некоторой группировки и т.д. Проблема в том, что этот SP работал нормально до тех пор, пока не вернул результаты за 1-2 минуты. А теперь вдруг его забирают 12-15 минут. Если я извлечу запрос из SP и выполнил его в студии управления, вручную установив те же параметры, он вернет результаты за 1-2 минуты, но SP займет очень много времени. Любая идея, что может произойти. Я попытался создать планы Actual Execution как Query, так и SP, но он не смог сгенерировать его из-за курсора. Любая идея, почему SP занимает столько времени, пока запрос отсутствует?

Ответы

Ответ 1

Это отпечаток параметра-нюхания. См. Здесь еще одно обсуждение этого вопроса; Плохая производительность плана выполнения хранимых процедур SQL - параметр sniffing

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

Рекомендуемое исправление для большинства ситуаций (хотя это зависит от структуры вашего запроса и sproc) - НЕ использовать ваши параметры непосредственно в ваших запросах, а скорее хранить их в локальных переменных, а затем использовать эти переменные в ваших запросах.

Ответ 2

из-за параметра sniffing. прежде всего объявить временную переменную и установить значение входящей переменной для переменной temp и использовать временную переменную во всем приложении. Ниже приведен пример.

ALTER PROCEDURE [dbo].[Sp_GetAllCustomerRecords]
@customerId INT 
AS
declare @customerIdTemp INT
set @customerIdTemp = @customerId
BEGIN
SELECT * 
FROM   Customers e Where
CustomerId = @customerIdTemp 
End

попробуйте этот подход

Ответ 3

Я бы также посмотрел на параметр sniffing. Может быть, proc должен обрабатывать параметры slighlty по-разному.

Ответ 4

Попробуйте перекомпилировать sproc, чтобы остановить любой сохраненный план запросов

exec sp_recompile 'YourSproc'

Затем запустите ваш sproc, чтобы использовать разумные параметры.

Также сравните фактические планы выполнения между двумя методами выполнения запроса.

Возможно, стоит пересчитать любую статистику.

Ответ 5

Обычно я начинаю устранять проблемы, связанные с этим, используя msgstr "print getdate() + '- step'". Это помогает мне сузить то, что занимает больше всего времени. Вы можете сравнить, где вы запускаете его из анализатора запросов и узко вниз, где проблема.

Ответ 6

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

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

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

Ответ 7

Для начала это не похоже на то, что SQL будет работать слишком хорошо в любом случае на основе использования нескольких временных таблиц (может храниться в памяти или сохраняться в tempdb - все, что решает SQL Server), и использование курсоров.

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

Что касается того, почему SP занимает больше времени, чем запрос - трудно сказать. Есть ли такая же нагрузка на систему при каждом подходе? Если вы запускаете сам запрос при легкой загрузке, он будет лучше, чем при запуске SP при большой нагрузке.

Кроме того, чтобы гарантировать, что запрос действительно быстрее, чем SP, вам необходимо исключить кеширование данных/выполнения, что делает запрос быстрее для последующих запусков. Вы можете очистить кеш, используя:

DBCC FREEPROCCACHE
DBCC DROPCLEANBUFFERS

Но это делается только на сервере dev/test db, а не на производстве. Затем запустите запрос, запишите статистику (например, из профилировщика). Снова очистите кеш. Запустите SP и сравните статистику.

Ответ 8

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

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

Ответ 9

Я тоже столкнулся с проблемой, когда нам приходилось создавать некоторые временные таблицы, а затем манипулировать ими приходилось вычислять некоторые значения на основе правил и, наконец, вставлять вычисленные значения в третью таблицу. Это все, если положить в один SP, занимал около 20-25 минут. Таким образом, чтобы оптимизировать его дальше, мы сломали sp на 3 разных sp, и общее время, которое теперь было занято, составляло около 6-8 минут. Просто определите шаги, которые участвуют во всем процессе, и как разбить их на разные sp. Разумеется, используя этот подход, общее время, затрачиваемое на весь процесс, будет уменьшаться.

Ответ 10

Перезапустите сервер или систему SQL, это было решено для меня.

Ответ 11

Я бы предположил, что проблема связана с типом таблицы temp (префикС#). Эта временная таблица содержит данные для этого сеанса базы данных. Когда вы запускаете его через приложение, таблица temp удаляется и воссоздается.
Вы можете обнаружить, что при работе в SSMS он сохраняет данные сеанса и обновляет таблицу вместо ее создания. Надеюсь, что помогает:)