Зберігається процедура повільно при виклику з Інтернету, швидко з Management Studio


97

Я зберігав процедуру, яка шалено закінчується кожен раз, коли її викликають із веб-програми.

Я запустив Sql Profiler і простежив дзвінки, що закінчились, і нарешті з'ясував такі речі:

  1. Коли виконуються оператори з MS SQL Management Studio, з тими ж аргументами (насправді я скопіював виклик процедури із трасування профілю sql і запустив його): він закінчується за 5 ~ 6 секунд в середньому.
  2. Але при виклику з веб-програми це займає понад 30 секунд (у сліді), тому на той час у моєї веб-сторінки фактично закінчується час.

Окрім того, що у моєї веб-програми є власний користувач, все рівно однакове (одна і та ж база даних, підключення, сервер тощо), я також спробував запустити запит безпосередньо в студії з користувачем веб-програми, і це займає не більше 6 сек.

Як мені дізнатися, що відбувається?

Я припускаю, що це не має нічого спільного з тим, що ми використовуємо шари BLL> DAL або адаптери таблиці, оскільки трасування чітко показує, що затримка знаходиться у фактичній процедурі. Це все, що я можу придумати.

EDIT Я дізнався за цим посиланням, що ADO.NET встановлює ARITHABORTзначення true - що добре протягом більшої частини часу, але іноді це трапляється, і пропонується навколо - додати with recompileопцію до збереженого proc. У моєму випадку це не працює, але я підозрюю, що це щось дуже схоже на це. Хтось знає, чим ще займається ADO.NET або де я можу знайти специфікацію?


1
Це може бути пов’язано з тим, скільки даних повертається?
Barry Kaye

@Barry: Ні, оскільки я запускаю ту саму процедуру (скопійовану також із трасування - маючи на увазі ті самі параметри) в студії управління, вона запускається протягом 6 секунд.
iamserious

@Jayantha: Справа НЕ в тому, що sp повільний, а в ЧОМУ між ado.net і sql. Я не бачу, як sp може змінити ситуацію.
iamserious

2
Чи повертає SP багато даних, наприклад стовпці image / text / varchar (max)? Кількість даних, що споживаються на клієнті, буде величезним, що займе багато часу. SSMS відсікає ці набори результатів у більш ефективній справі.
Тім Шмельтер

Відповіді:


79

Раніше у мене виникала подібна проблема, тому я дуже хочу побачити вирішення цього питання. Коментар Аарона Бертрана щодо ОП призвів до того, що час запиту закінчився при виконанні з Інтернету, але надшвидкий при виконанні із СУБД , і хоча запитання не є дублікатом, відповідь цілком може стосуватися вашої ситуації.

По суті, це схоже на те, що SQL Server може мати пошкоджений кешований план виконання. Ви потрапляєте на поганий план із вашим веб-сервером, але SSMS потрапляє на інший план, оскільки на прапорі ARITHABORT є інше налаштування (яке в іншому випадку не вплине на ваш конкретний запит / збережений процес).

Див. Розділ ADO.NET, що викликає збережену процедуру T-SQL, викликає SqlTimeoutException для іншого прикладу, з більш повним поясненням та вирішенням.


Ось декілька цікавих підказок, прочитаємо більше про них і повернемося за кілька .. спасибі.
iamserious

44
Привіт, Очищення кеш-пам’яті DBCC DROPCLEANBUFFERSі DBCC FREEPROCCACHEтрюк! Я припускаю, що план виконання був якимось чином пошкоджений або не оновлений. Я сумнівний, що це постійне виправлення, якщо воно може бути пошкоджене один раз, воно може зробити це знову. Тож я все ще розглядаю цілком ймовірні причини. Оскільки веб-програма знову працює, мені не потрібно відчувати тиск. Велике спасибі.
iamserious

2
@iamserious - ти прибив це завдяки! Після зміни моєї збереженої процедури у мене виникла проблема з таймаутом. Потім я запустив дві команди DBCC, про які ви згадали вище, і це вирішило проблему.
Induster

5
@Mangist: Тому що це складне питання, немає срібної кулі, але ви можете спробувати використовувати OPTIMIZE FORабо OPTION(Recompile)підказки запитів на запити, які викликають проблеми. У цій статті поглиблено розглядається проблема. Якщо Entity Framework генерує ваші запити, ця публікація, здається, надає спосіб додати підказку до ваших запитів.
StriplingWarrior

8
Замість запуску DBCC DROPCLEANBUFFERS та DBCC FREEPROCCACHE, які очистять ВСІ плани виконання, ви можете скинути та відтворити проблему, що зберігається.
jnoreiga

50

Я також відчуваю, що запити повільно та швидко працюють в Інтернеті в SSMS, і врешті-решт я з'ясував, що проблема полягала в чомусь, що називається нюханням параметрів.

Для мене виправлення полягало в тому, щоб змінити всі параметри, які використовуються в sproc, на локальні змінні.

напр. зміни:

ALTER PROCEDURE [dbo].[sproc] 
    @param1 int,
AS
SELECT * FROM Table WHERE ID = @param1 

до:

ALTER PROCEDURE [dbo].[sproc] 
    @param1 int,
AS
DECLARE @param1a int
SET @param1a = @param1
SELECT * FROM Table WHERE ID = @param1a

Здається дивним, але це вирішило мою проблему.


3
Ого, у мене була та сама проблема, і я не вірив, що це спрацює, але це так.
Lac Ho

1
Зейн, ти знаєш, чи це назавжди вирішить проблему, або вона може повернутися? Дякую!
Лак Хо

1
З моменту внесення змін я не мав жодних проблем зі швидкістю збереженої процедури.
Зейн

1
Ого, це теж вирішило мою проблему! Це МОЖЕ БИТТИ помилкою на сервері sql. Навіщо змушувати sql-авторів стрибати через цей безглуздий обруч, коли MSSQL може внутрішньо перетворити на локальний під капотом, для ВЕЛИЧЕЗНОГО підвищення продуктивності?
HerrimanCoder

3
Можливо, зміна proc призводить до створення нового плану виконання, тому рішення насправді не копіює вхідну змінну до локальної змінної, а просто примушує генерувати новий план виконання (як пояснюється у прийнятому рішенні)?
Гарланд Папа,

10

Щоб не спам, але, як сподіваємося, корисне рішення для інших, наша система бачила високий рівень очікування.

Я спробував встановити збережену процедуру для перекомпіляції за допомогою, sp_recompileі це вирішило проблему для одного SP.

Врешті-решт, була більша кількість ІП, які вичерпали час, багато з яких ніколи раніше цього не робили, використовуючи, DBCC DROPCLEANBUFFERSі DBBC FREEPROCCACHEчастота інцидентів значно впала - все ще є поодинокі випадки, деякі, де я підозрюю, що планується відновлення плану деякий час, і деякі з них, коли СП справді недостатньо ефективні і потребують повторної оцінки.


1
Дякую за це Позначення процедури перекомпіляції за допомогою команди sp_recompile спрацювало для мене, коли DBCC DROPCLEANBUFFERSі DBCC FREEPROCCACHEне мало значення.
Стів

4

Чи може бути, що деякі інші виклики БД, здійснені до викликів веб-додатків, підтримують транзакцію відкритою? Це може бути причиною для цього SP, щоб зачекати, коли його викличе веб-програма. Я кажу, ізолюйте виклик у веб-програмі (розмістіть його на новій сторінці), щоб переконатися, що деякі попередні дії у веб-програмі спричиняють цю проблему.


1
Привіт @Tundey, я ізолював дзвінок, і він все ще триває приблизно 30 сек. отже, це має бути щось між спілкуванням, я думаю?
iamserious

1

Просто перекомпіляція збереженої процедури (функція таблиці в моєму випадку) спрацювала для мене


1

подібно @Zane сказав, що це може бути через нюхання параметрів. Я відчув однакову поведінку, і я подивився план виконання процедури та всі оператори sp підряд (скопіював усі оператори з процедури, оголосив параметри як змінні та призначив ті самі значення для змінної, що і параметри мали). Однак план страти виглядав зовсім по-іншому. Виконання sp зайняло 3-4 секунди, а оператори поспіль із точно однаковими значеннями миттєво повернули.

план виконання

Після деякого гуглювання я знайшов цікаве читання про цю поведінку: повільно в додатку, швидко в SSMS?

Під час компіляції процедури SQL Server не знає, що значення @fromdate змінюється, але компілює процедуру, припускаючи, що @fromdate має значення NULL. Оскільки всі порівняння з NULL дають UNKNOWN, запит не може повернути жодного рядка взагалі, якщо @fromdate все ще має це значення під час виконання. Якщо SQL Server прийме вхідне значення як остаточну істину, він може побудувати план лише з постійним скануванням, яке взагалі не отримує доступ до таблиці (запустіть запит SELECT * FROM Orders WHERE OrderDate> NULL, щоб побачити приклад цього) . Але SQL Server повинен генерувати план, який повертає правильний результат, незалежно від того, яке значення має @fromdate під час виконання. З іншого боку, немає зобов’язань будувати план, який є найкращим для всіх цінностей. Таким чином, оскільки припущення полягає в тому, що не буде повернуто жодних рядків, SQL Server задовольняється пошуком індексу.

Проблема полягала в тому, що у мене були параметри, які можна залишити нульовими, і якщо вони були передані як нульові, було б ініціалізовано значення за замовчуванням.

create procedure dbo.procedure
    @dateTo datetime = null
begin
    if (@dateTo is null)
    begin
        select @dateTo  = GETUTCDATE()
    end

    select foo
    from dbo.table
    where createdDate < @dateTo
end

Після того, як я змінив його на

create procedure dbo.procedure
    @dateTo datetime = null
begin
    declare @to datetime = coalesce(@dateTo, getutcdate())

    select foo
    from dbo.table
    where createdDate < @to
end 

це знову спрацювало як шарм.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.