Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.10.09;
Скачать: CL | DM;

Вниз

Скорость работы хранимых процедур значительно ниже запросов   Найти похожие ветки 

 
Malign   (2005-08-30 11:27) [0]

Добрый день.

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

Выполняемый  запрос сравнительно большой (около 100 строк). При исполнении запроса на киенте на его исполнение уходит 20-40 секунд, при вызове процедуры (текст тотже) 3-5 минут.

Тестировал на 2-х различных серверах (результат идентичен).

При этом:
-оптимизация запросов включена,
-план выполнения запросов идентичен,
-при включении статистики видно, что количество "обращений" к ресурсам у ХП в несколько СОТЕН тысяч больше чем у запроса.

Вопрос, как заставить процедуру работать с нормальной скоростью??? (требуется сохранить открытый интерфейс(а не перетаскивать все на клиенты))


 
Nikolay M. ©   (2005-08-30 11:46) [1]

1. Перекомпилить процедуру, сбросить кэш плана выполнения ХП.
2. Расставить в ХП хинты, индексы, если используются #-таблицы - там свои заморочки.
3. Привести текст ХП.


 
Ega23 ©   (2005-08-30 11:56) [2]

А при многократном обращении?


 
АлексейК   (2005-08-30 12:13) [3]

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

Выполняемый  запрос сравнительно большой (около 100 строк). При исполнении запроса на киенте на его исполнение уходит 20-40 секунд, при вызове процедуры (текст тотже) 3-5 минут.


Ничего подобного ни разу не встречал, и по логике такого быть не должно, смысла в хранимых процедурах тогды бы не было. Для интереса выполнил пробный тест, набодобие:
select ....
from ....
where ....
go
create procedure test
as
select ....
from ....
where ....
go
exec test

Даже в этом случае, учитывая время компиляции процедуры, разницы во времени выполнения запросов не обнаружил. У вас же она отличатеся в разы, интересно было бы посмотреть на код этой самой процедуры. Кстати а название процедуры не начинается с dt_


 
Nikolay M. ©   (2005-08-30 12:53) [4]


> Кстати а название процедуры не начинается с dt_

Может, с "sp_"?


> Ничего подобного ни разу не встречал

Мало с ms sql работали, видимо.


> по логике такого быть не должно

У сервера своя логика и она утверждает, что такое очень даже может быть.


> смысла в хранимых процедурах тогды бы не было

Назначение ХП не только в том, чтобы быть обертками простых запросов.


> Для интереса выполнил пробный тест

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


 
Malign   (2005-08-30 13:42) [5]

>1. Перекомпилить процедуру, сбросить кэш плана выполнения ХП.

Перекомпиливал, сбрасывал, переиминовывал (как только не извращался)

>2. Расставить в ХП хинты, индексы, если используются #-таблицы -> там свои заморочки.
Темповые там не используются.

>3. Привести текст ХП.

Вот основная часть процедуры (она чуть пошустрей работает но тенденция таже)

+++++++++++++++++++++++++++++++++++++++++++=

CREATE PROCEDURE Select_xxx
@BEG DATETIME,  
@END DATETIME,
@DEPART INT
AS  

SET DATEFORMAT dmy

SELECT S.SmenaDate as "DATE",  E.Etalon_ID as PROP_ID ,  E.id as PROP,  E.TABEL, E.FIO,    E.Dolgnost ,    MAX(S.DateOfPasses) as "DateOfPasses",  E.DEPART as "DEPART" ,  D.Name  AS "DEPARTNAME",
  (ltrim(str(datepart(hh, ((T.End_ -MAX(S.DateOfPasses))-
            isnull((select top 1 (T.End_Din-T.Beg_Din)
     FROM SmenParams SE
 WHERE  (SE.TA_ID=T.[ID]) AND  (SE.TypeAccount = 1)
          and (MAX(S.DateOfPasses)<T.Beg_Din) ), 0)-
            isnull((select  top 1  (T.End_Din-MAX(S.DateOfPasses))
     FROM SmenParams SE
 WHERE  (SE.TA_ID=T.[ID]) AND  (SE.TypeAccount = 1)
          and (MAX(S.DateOfPasses)>T.Beg_Din) and (MAX(S.DateOfPasses)<T.End_Din)), 0)
 ) )))+":" +
 (case ltrim(str(datepart(mi, ((T.End_ -MAX(S.DateOfPasses))-isnull((select   top 1 (T.End_Din-T.Beg_Din)
     FROM SmenParams SE
 WHERE  (SE.TA_ID=T.[ID]) AND  (SE.TypeAccount = 1)
          and (MAX(S.DateOfPasses)<T.Beg_Din) ), 0)-
            isnull((select  top 1  (T.End_Din-MAX(S.DateOfPasses))
     FROM SmenParams SE
 WHERE  (SE.TA_ID=T.[ID]) AND  (SE.TypeAccount = 1)
          and (MAX(S.DateOfPasses)>T.Beg_Din) and (MAX(S.DateOfPasses)<T.End_Din)), 0)
) )))
 when 0 then "00"
when 1 then "01"
when 2 then "02"
when 3 then "03"
 when 4 then "04"
when 5 then "05"
when 6 then "06"
when 7 then "07"
 when 8 then "08"
when 9 then "09"
else ltrim(str(datepart(mi, ((T.End_ -MAX(S.DateOfPasses))-isnull((select  top 1  (T.End_Din-T.Beg_Din)
     FROM SmenParams SE
 WHERE  (SE.TA_ID=T.[ID]) AND  (SE.TypeAccount = 1) -- Доработанно для исключения из времени недоработки обеда
          and (MAX(S.DateOfPasses)<T.Beg_Din) ), 0)-
            isnull((select  top 1  (T.End_Din-MAX(S.DateOfPasses))
     FROM SmenParams SE
 WHERE  (SE.TA_ID=T.[ID]) AND  (SE.TypeAccount = 1)
          and (MAX(S.DateOfPasses)>T.Beg_Din) and (MAX(S.DateOfPasses)<T.End_Din)), 0)
) ))) end)) as "ned"
       FROM     TabAccount T INNER JOIN
            SmenParams S ON T.ID = S.TA_ID INNER JOIN
            etalon E ON T.PROP_ID = E.ETALON_ID INNER JOIN
            depart D ON E.depart = D.ID
       WHERE (S.TypeAccount = 1) AND (S.Slug_Flag = 0)  AND (S.SmenaDate >= @BEG) AND (S.SmenaDate <= @END)
                  and (E.free<>1) and ((E.DEPART=@DEPART) OR (@DEPART<=0))
 AND ((SELECT COUNT(*) FROM DemandsForTabAccount DFT WHERE (DFT.PROP_ID=E.ETALON_ID) AND (S.SmenaDate>=DFT.BEG_)
   AND (S.SmenaDate<=DFT.END_))=0 )
GROUP BY  E.DEPART, S.SmenaDate,T.[YEAR], T.MES, T.[DATE], E.id,   E.Etalon_ID,  E.fio,   T.End_ , T.Begin_,   D.Name , T.ID, T.Beg_Din, T.End_Din, E.Dolgnost, E.TABEL
-- для сортировки по продазделению пренес   E.DEPART на перую позицию
HAVING  ((SELECT COUNT(*)   FROM    SmenParams SE WHERE  (SE.TA_ID=T.[ID]) AND  (SE.TypeAccount = 0)  
 AND  (MAX(S.DateOfPasses) <=(SE.DateOfPasses))   AND (T.End_ >SE.DateOfPasses) ) =0)
     AND (T.End_ >max(S.DateOfPasses))  AND   (T.Begin_ <= max(S.DateOfPasses))
               and (((datepart(ss,T.End_ -MAX(S.DateOfPasses)))<59) -- отсечение времени  
    and ((datepart(mi,T.End_ -MAX(S.DateOfPasses)))<>0) or ((datepart(hh,T.End_ -MAX(S.DateOfPasses)))<>0))
               AND (datepart(day, (T.end_-T.begin_))<=1)  -- Для исключения круглосуточных смен
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++


 
АлексейК   (2005-08-30 13:50) [6]

Nikolay M. ©   (30.08.05 12:53) [4]

Может, с "sp_"?
Верно, ошибся с sp.

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

> смысла в хранимых процедурах тогды бы не было

Назначение ХП не только в том, чтобы быть обертками простых запросов.


Однако, если бы они уменьшали бы производительность в разы, то я бы обошолся и без них.


 
Malign   (2005-08-30 13:50) [7]

Процедура расчитывает отработанные временные показатели и имеет дело с большими объемами данных.


 
Malign   (2005-08-30 13:54) [8]

>А при многократном обращении?

При многократном обращении, естественно быстрее, но разница в порядке "отсавания ХП" остается.


 
Nikolay M. ©   (2005-08-30 13:58) [9]

Процедура кушает на вход параметры, которые используются в WHERE - т.е. уже нельзя говорить о том, что ХП является оберткой простого селекта.
Поскольку при построении плана выполнения ХП конкретные значения параметров неизвестны, сервер будет исходить из того, что значения могут быть любыми и этот план, скорее всего, будет выбран не оптимальным, а иногда даже может быть выбран Table scan вместо банального Index seek. При построении же плана отдельного запроса (не в ХП), когда параметры известны, сервер будет использовать статистику. Попробуй:
1. При создании указать WITH RECOMPILE
2. Ради эксперимента вместо параметров подставить конкретные значения.
3. Расставить хинтами необходимые индексы.

ПС
Выглядит, конечно, страшновато. А обязательно это делать одним запросом?


 
Nikolay M. ©   (2005-08-30 14:35) [10]


> АлексейК   (30.08.05 13:50) [6]
> Может и мало, но все же не встречался, что бы один и тот
> же скрипт отдельно и завернутый в процедуру отличался по
> времени выполнения в разы. А поскольку вы утверждаете, что
> такое явление вполне нормально, хотелось узнать в каком
> случае это будет происходить.

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


 
Malign   (2005-08-30 15:29) [11]


> 1. При создании указать WITH RECOMPILE
> 2. Ради эксперимента вместо параметров подставить конкретные
> значения.
> 3. Расставить хинтами необходимые индексы.


1.Рекопайл не помог.

2.Действительно с конкретными значениями все летает :-)

3.Поставил пару хинтов и процедура стала значительно быстрее (!!)
и практически сравнялась с запросом :-)
(хотя при простановке индексов хинтами в запросе он стал немого тормазнутей (при вводе не тех индексов))

Вообщем все заработало приемлимо, пойду еще погоняю процедурку с другими индексами.

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

Всем спасибо,
отдельное Nikolay"ю ^|^.


 
Bless ©   (2005-08-30 15:41) [12]

Кстати, попробуй трюк, предложенный в
http://www.sql.ru/articles/mssql/2005/070704TechniqueForEnsuringPlanStabilityInSQLServer2000.shtml

А вдруг поможет и удастся обойтись без хинтов :).


 
Nikolay M. ©   (2005-08-30 15:53) [13]


> Malign

На здоровье, обращайся :)


> Bless ©   (30.08.05 15:41) [12]
> Кстати, попробуй трюк

Ненадежно, не всегда применимо и вызывает сдвиг по фазе в мозгах программистов следующих за тобой поколений :)
В итоге получается "нечто" вроде такого:
http://www.rsdn.ru/Forum/Message.aspx?mid=1320137&only=1
:))))


 
Bless ©   (2005-08-30 16:27) [14]

Nikolay M. [13]>
Да ладно. Я ж в порядке расширения кругозора :)
Кстати, по ссылке вполне читаемый код (правда, pop ebx потеряно). Хоть и не оптимальный.


 
Nikolay M. ©   (2005-08-30 16:35) [15]


> Bless ©   (30.08.05 16:27) [14]
> Да ладно. Я ж в порядке расширения кругозора :)

Ну, тогда другое дело :)


> Кстати, по ссылке вполне читаемый код (правда, pop ebx потеряно).
> Хоть и не оптимальный.

Согласен с мнением, что кг/ам :)


 
Bless ©   (2005-08-30 17:00) [16]

>Согласен с мнением, что кг/ам :)

Что-то я не уловил, что не так в том примере (кроме размера var-параметров)?
И что такое "ам"? :)


 
Nikolay M. ©   (2005-08-30 17:06) [17]


> Bless ©   (30.08.05 17:00) [16]

http://www.sokr.ru/?text=%EA%E3%2F%E0%EC&where=abbr&exact=on
это к вопросу об ассемблерных вставках


 
Bless ©   (2005-08-30 17:12) [18]

Nikolay M.[17]>

ЛОЛ!


 
АлексейК   (2005-08-31 05:02) [19]

Nikolay M. ©   (30.08.05 13:58) [9]

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

Malign   (30.08.05 15:29) [11]

Почитай статью "Информационная система и реляционная СУБД" в разделе проектирование на www.rsdn.ru, очень интересно когда оборотка собирается из 10 миллионов записей за 1-2 секунды, при этом прямой запрос отрабатывает 6 минут.


 
Nikolay M. ©   (2005-08-31 09:57) [20]


> АлексейК   (31.08.05 05:02) [19]
> Речь в начале шла об одном и том же запросе

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



Страницы: 1 вся ветка

Текущий архив: 2005.10.09;
Скачать: CL | DM;

Наверх




Память: 0.54 MB
Время: 0.044 c
6-1118642221
silvestr
2005-06-13 09:57
2005.10.09
winpcap


2-1125325409
SergP.
2005-08-29 18:23
2005.10.09
Проблема с SQL запросом.


6-1102146918
6h
2004-12-04 10:55
2005.10.09
Как мне отослать SMS сообщение на сотовый


9-1117549211
new1
2005-05-31 18:20
2005.10.09
Динамическое освещение. Лайт Мэпы.


1-1126891114
ArtemESC
2005-09-16 21:18
2005.10.09
Сетевые данные