Оптимизация условия WHERE

tentra

SELECT bla.bla.bla... FROm bla.bla.bla.
WHERE ordernum='bla.bla.bla'
AND ((dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = <b>1</b> AND dbo.TWORKFLOWENTRYASSG.ASGNTOOBJID = @P_USERID)
 OR (dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = <b>25</b> AND dbo.TWORKFLOWENTRY.CREATORTYPE = 'USER' AND dbo.TWORKFLOWENTRY.CREATORID = @P_USERID)
 OR (dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = <b>26</b> AND dbo.TWORKFLOWENTRY.ORIGINATORTYPE = 'USER' AND dbo.TWORKFLOWENTRY.ORIGINATORID = @P_USERID)
OR (dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = <b>29</b> AND <b>1</b> = (SELECT <b>1</b> FROM dbo.TUSER WHERE dbo.TWORKFLOWENTRYASSG.ASGNTOOBJID = dbo.TUSER.GROUPID AND dbo.TUSER.UNIQUEID = @P_USERID))
Запрос страшно тормозит ... именно из-за последнего условия
OR (dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = <b>29</b> AND EXISTS (SELECT <b>1</b> FROM dbo.TUSER WHERE dbo.TWORKFLOWENTRYASSG.ASGNTOOBJID = dbo.TUSER.GROUPID AND dbo.TUSER.UNIQUEID = @P_USERID)
Если убрать последнее условие, то выполняется за 2 секунды. Я Одного понять не могу, в базе нет ни одной записи с dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = 29, по идее скул не должен проверять условие EXISTS...Есть идеи, как можно оптимизировать условие WHERE. чтобы до exists не доходило?
22 ответа

tentra

План выполнения покажите.ЗЫ можно попробовать эти ORы переделать в union all. Но сначала ПЛАН!


tentra

план будет просто огрмный... я поскипал большой кусок кода...это запрос сам является одним из union (всего три таких запроса объединяются union)


tentra

могу еще добавить что таких условий
OR (dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = <b>29</b> AND EXISTS (SELECT <b>1</b> FROM dbo.TUSER WHERE dbo.TWORKFLOWENTRYASSG.ASGNTOOBJID = dbo.TUSER.GROUPID AND dbo.TUSER.UNIQUEID = @P_USERID)
несколько, dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = 30..50проверяющие exists данные в разых таблицах...при добавлении кадого такого условия запрос выполняется дольше на 3-4 секунды для кадого условия.ASGNTOOBJTYPE на данный момент есть только 1.Поэтому по идее эти условия не должны влиять, они должны отсечься сразу после проверки ASGNTOOBJTYPE.Пробовал сделать то же самое через case - оезультат такой же.


tentra

Блин, читать так неудобно. Алиасами пользоваться - есть гуд!
code SQL for food


tentra

А в конце запроса еще одной скобочки не хватает.
code SQL for food


tentra

насчет читать неудобно - соглачен... код не мой просто. Оптимизировать надо... вот голову ломаю... ничего не получается... а скобочку пропустил когда код сюда копировал...


tentra

В одном из последних хотфиксов для SP4 как раз пофиксили похожую проблему с CASE, поищите на сайте Майкрософта.Как вариант попробуйте
WHERE ordernum='bla.bla.bla'
AND dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE IN (<b>1</b>,<b>25</b>,<b>26</b>,<b>29</b>,...)
AND ((dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = <b>1</b> AND dbo.TWORKFLOWENTRYASSG.ASGNTOOBJID = @P_USERID)
...


tentra

В одном из последних хотфиксов для SP4 как раз пофиксили похожую проблему с CASE, поищите на сайте Майкрософта.Как вариант попробуйте
WHERE ordernum='bla.bla.bla'
AND dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE IN (<b>1</b>,<b>25</b>,<b>26</b>,<b>29</b>,...)
AND ((dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = <b>1</b> AND dbo.TWORKFLOWENTRYASSG.ASGNTOOBJID = @P_USERID)
...
спасибо - попробую...забыл добавить - сервак 2005


tentra

Статистику обновляли?


tentra

Статистику обновляли?
да.


tentra

Возможно я не прав. Кажется, что проверка условий в where не гарантируется именно в порядке их описания в запросе. И стандртом не предопределяется. Отдается на откуп сервера (оптимизатора). :)


tentra

Кстати, можно через CASE проверять dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = 25 а в нем уже остальные условия. В таком случае подзапросы точно не будут выполняться без необходимости
code SQL for food


tentra

я пробовал конструкцию типа
AND (<b>1</b>=CASE dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE
		WHEN <b>29</b> THEN (SELECT <b>1</b> FROM dbo.TUSER WHERE dbo.TWORKFLOWENTRYASSG.ASGNTOOBJID = dbo.TUSER.GROUPID AND dbo.TUSER.UNIQUEID = @P_USERID)
		WHEN <b>27</b> THEN (SELECT <b>1</b> FROM dbo.TTEAMMEMBER WHERE dbo.TWORKFLOWENTRYASSG.ASGNTOOBJID = dbo.TTEAMMEMBER.TEAMID AND dbo.TTEAMMEMBER.USERID = @P_USERID)
		WHEN <b>28</b> THEN (SELECT <b>1</b> FROM dbo.TUSER WHERE dbo.TWORKFLOWENTRYASSG.ASGNTOOBJID = dbo.TUSER.TITLEID AND dbo.TUSER.UNIQUEID = @P_USERID)
		WHEN <b>30</b> THEN (SELECT <b>1</b> FROM dbo.TUSERROLE WHERE dbo.TWORKFLOWENTRYASSG.ASGNTOOBJID = dbo.TUSERROLE.ROLEID AND dbo.TUSERROLE.USERID = @P_USERID)
		ELSE <b>0</b>
		END
	)
вроде бы так...на производительность не повлияло абсолютно... тоже самое как и через OR.Я так понимаю здесь остается только план колупать ?


tentra

dbo.TUSER в left join поместить?


tentra

Оптимизатор MS SQL - стоимостной (т.е. строит план на основании стоимости операций ввода-вывода и стоимости процессорных ресурсов), это он решает, в каком порядке соединять таблицы, какие индексы использовать, в каком порядке вычислять предикаты и т.д. - в результате получается план выполнения. С него по-хорошему и надо начинать!


tentra

dbo.TUSER в left join поместить?
Вот так, по-моему, как у автора в первом посте, но без подзапроса:
SELECT * FROm (bla.bla.bla... ) LEFT JOIN dbo.TUSER ON dbo.TWORKFLOWENTRYASSG.ASGNTOOBJID = dbo.TUSER.GROUPID AND dbo.TUSER.UNIQUEID = @P_USERID
WHERE ordernum='bla.bla.bla'
AND ((dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = <b>1</b> AND dbo.TWORKFLOWENTRYASSG.ASGNTOOBJID = @P_USERID)
 OR (dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = <b>25</b> AND dbo.TWORKFLOWENTRY.CREATORTYPE = 'USER' AND dbo.TWORKFLOWENTRY.CREATORID = @P_USERID)
 OR (dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = <b>26</b> AND dbo.TWORKFLOWENTRY.ORIGINATORTYPE = 'USER' AND dbo.TWORKFLOWENTRY.ORIGINATORID = @P_USERID)
 OR (dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = <b>29</b> AND dbo.TUSER.GROUPID IS NOT NULL)


tentra

Вот так, по-моему, как у автора в первом посте, но без подзапроса:
SELECT * FROm (bla.bla.bla... ) LEFT JOIN dbo.TUSER ON dbo.TWORKFLOWENTRYASSG.ASGNTOOBJID = dbo.TUSER.GROUPID AND dbo.TUSER.UNIQUEID = @P_USERID
WHERE ordernum='bla.bla.bla'
AND ((dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = <b>1</b> AND dbo.TWORKFLOWENTRYASSG.ASGNTOOBJID = @P_USERID)
 OR (dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = <b>25</b> AND dbo.TWORKFLOWENTRY.CREATORTYPE = 'USER' AND dbo.TWORKFLOWENTRY.CREATORID = @P_USERID)
 OR (dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = <b>26</b> AND dbo.TWORKFLOWENTRY.ORIGINATORTYPE = 'USER' AND dbo.TWORKFLOWENTRY.ORIGINATORID = @P_USERID)
 OR (dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = <b>29</b> AND dbo.TUSER.GROUPID IS NOT NULL)
к сожалению так не пойдет. таких условий очень много - Более 50, не джоинить же 50 таблиц... к тому же в некоторых условиях надо проверять условие в нескольких таблиц ах


tentra

к сожалению так не пойдет. таких условий очень много - Более 50, не джоинить же 50 таблиц... к тому же в некоторых условиях надо проверять условие в нескольких таблиц ах
А попробовать? Соединение 50 таблиц по ключу - ерунда! :) Главное - чтобы при этом не возникало перемножение, т.е. должно быть отношение 1:1


tentra

А попробовать? Соединение 50 таблиц по ключу - ерунда! :) Главное - чтобы при этом не возникало перемножение, т.е. должно быть отношение 1:1
Фрагмент первого поста
<b>1</b> = (SELECT <b>1</b> FROM dbo.TUSER ...)
говорит о том, что соотношение именно 1:1


tentra

Фрагмент первого поста
<b>1</b> = (SELECT <b>1</b> FROM dbo.TUSER ...)
говорит о том, что соотношение именно 1:1
там вместо 1= (select 1)должно быть exists (select 1)


tentra

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


tentra

А если так попробовать:SELECT bla.bla.bla... FROm bla.bla.bla....OR (exists(SELECT 1 FROM dbo.TUSER WHERE dbo.TWORKFLOWENTRYASSG.ASGNTOOBJTYPE = 29 dbo.TWORKFLOWENTRYASSG.ASGNTOOBJID = dbo.TUSER.GROUPID AND dbo.TUSER.UNIQUEID = @P_USERID)) P.S. Приведите план хотя бы указанного вами в начале топика куска кода.