Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Базы";
Текущий архив: 2005.10.09;
Скачать: [xml.tar.bz2];

Вниз

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

 
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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.52 MB
Время: 0.014 c
14-1127126807
pazitron_brain
2005-09-19 14:46
2005.10.09
GTA : VC по сети.


1-1127198832
ZeroDivide
2005-09-20 10:47
2005.10.09
Винда не может завершить работу, когда мой процесс запущен !


2-1125459771
AlexanderS
2005-08-31 07:42
2005.10.09
Ошибка с OpenDialog


1-1127028683
vidiv
2005-09-18 11:31
2005.10.09
Распознование ссылок в тексте


14-1127216130
Profi
2005-09-20 15:35
2005.10.09
Нужна помощь с железом





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский