Чем отличаются эти два sql-запроса?

pitrik2

это внешние композитные ключи (по двум полям)
первый запрос генерит hibernate и работает он намноооого дольше второго
вопрос, правильно ли я понимаю что запросы идентичны?
если правильно, то значит оракл туповат?
хоть я хинт и не подсуну hibernate-у, но все таки очень интересно, можно ли первый запрос подправить хинтами?
ну и самое сложное: как обуздать hibernate?
первый запрос

select exerepenti0_.orig_id as col_0_0_, exerepenti0_.system_id as col_0_1_, orderentit1_.orig_id as col_1_0_, orderentit1_.system_id as col_1_1_
from tExerep exerepenti0_
left outer join tOrder orderentit1_
on exerepenti0_.ORDER_ORIG_ID=orderentit1_.orig_id and exerepenti0_.SYSTEM_ID=orderentit1_.system_id
where
exerepenti0_.system_id=1 and orderentit1_.ORIG_ID='315905723'
or exerepenti0_.system_id=1 and orderentit1_.parent_orig_id='315905723'
or exerepenti0_.system_id=1 and orderentit1_.root_orig_id='315905723'

первый запрос

select exerepenti0_.orig_id as col_0_0_, exerepenti0_.system_id as col_0_1_, orderentit1_.orig_id as col_1_0_, orderentit1_.system_id as col_1_1_
from tExerep exerepenti0_
left outer join tOrder orderentit1_
on exerepenti0_.ORDER_ORIG_ID=orderentit1_.orig_id and exerepenti0_.SYSTEM_ID=orderentit1_.system_id
where
orderentit1_.system_id=1 and orderentit1_.ORIG_ID='315905723'
or orderentit1_.system_id=1 and orderentit1_.parent_orig_id='315905723'
or orderentit1_.system_id=1 and orderentit1_.root_orig_id='315905723'

план первого:

Operation Object Name Rows Bytes Cost

SELECT STATEMENT Optimizer Mode=ALL_ROWS 711 K 3899
FILTER
HASH JOIN RIGHT OUTER 711 K 65 M 3899
INDEX FAST FULL SCAN IDX_TORDER_TREE 2 K 76 K 5
TABLE ACCESS FULL TEXEREP 711 K 43 M 3871

план второго:

Operation Object Name Rows Bytes Cost Object Node In/Out PStart PStop

SELECT STATEMENT Optimizer Mode=ALL_ROWS 635 12
TABLE ACCESS BY INDEX ROWID TEXEREP 300 18 K 5
NESTED LOOPS 635 60 K 12
INDEX FAST FULL SCAN IDX_TORDER_TREE 2 66 5
INDEX RANGE SCAN IDX_TEXEREP_ORD 6 2

klyv

с задачей "найти 10 отличий в запросах" не справился...
они что, одинаковы до символа?
если вопрос в том, почему запросы, поступившие по разным каналам, по разному компилируются (и, соотв., выполняются то есть 2 пути:
- проверить, одинаковые ли соединения используются для передачи запросов (возможны всякие настройки, итпъ)
- смириться

pitrik2

с задачей "найти 10 отличий в запросах" не справился...
они что, одинаковы до символа?
ой
я думал это сразу видно
в последних трех строчках связка по полю SYSTEM_ID идет по разным сущностям
как с хибернейтом справиться нашел кстати
щас все летает
инересно все таки идентичны запросы или нет....

klyv

ой
я думал это сразу видно
в последних трех строчках связка по полю SYSTEM_ID идет по разным сущностям
Пардон, не углядел...
как с хибернейтом справиться нашел кстати
щас все летает
инересно все таки идентичны запросы или нет....
Как справился?
Имо, запросы должны компилиться абсолютно одинаково.

0000

Так думаю читабельнее

select A.id, ...
from A left outer join B on A.a = B.a and A.b = B.b
where B.b = 1 and B.a = '315905723' or
B.b = 1 and B.c ='315905723' or
B.b = 1 and B.d ='315905723'

А вообще план запроса наводит на размышления, что вот так было бы быстрее.
Но это при условии что запросы идентичны (кажется да, но может что то упустил)

with B2 as
(select * from B where B.b = 1 and B.a = '315905723' or ...)
select A.id, ...
from A left outer join B2 on A.a = B2.a and A.b = B2.b

pitrik2

все
у меня крыша едет

select /*+ index(exerepenti0_ idx_texerep_ord)*/
exerepenti0_.orig_id as col_0_0_, exerepenti0_.system_id as col_0_1_, orderentit1_.orig_id as col_1_0_, orderentit1_.system_id as col_1_1_
from tExerep exerepenti0_
left outer join tOrder orderentit1_
on exerepenti0_.ORDER_ORIG_ID=orderentit1_.orig_id and exerepenti0_.SYSTEM_ID=orderentit1_.system_id
where
exerepenti0_.system_id=1 and exerepenti0_.ORDER_ORIG_ID='315905723'


select /*+ index(exerepenti0_ idx_texerep_ord)*/
exerepenti0_.orig_id as col_0_0_, exerepenti0_.system_id as col_0_1_, orderentit1_.orig_id as col_1_0_, orderentit1_.system_id as col_1_1_
from tExerep exerepenti0_
left outer join tOrder orderentit1_
on exerepenti0_.ORDER_ORIG_ID=orderentit1_.orig_id and exerepenti0_.SYSTEM_ID=orderentit1_.system_id
where
exerepenti0_.system_id=1 and exerepenti0_.ORDER_ORIG_ID='315905723'
or orderentit1_.system_id=1 and orderentit1_.ORIG_ID='315905723'

второй запрос отличается лишней строчкой в конце
у первого запроса кост 8
у второго - 314862
эти два запроса похоже все таки разные
изза внешнего джойна и ИЛИ в условии
первый запрос он делает INDEX RANGE SCAN по индексу внешнего ключа - все зашибись
второй запрос он делает INDEX FULL SCAN по этому же самому индексу
зачем FULL? не понимаю :(
пмойму надо делать тот же самый RANGE, а потом с мерджить или вернее с-ИЛИ-ить результы

pitrik2

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

0000

Первый то же не обязывает - если строка не найдена (сработал outer то B.* все NULL будет и where их откинет.
outer вообще не пойму зачем.

0000

Опять перепишу (это второй запрос)

select /*?*/ ...
from A left outer join B ...
where A.a = C1 and A.b = C2 or ...

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

Vantucha

по планам не видно cardinaltiy и порядок Access/Filter predicates
по каким полям построен индекс IDX_TEXEREP_ORD?
статистика собрана?

pitrik2

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

zya369

 select exerepenti0_.orig_id as col_0_0_, exerepenti0_.system_id as col_0_1_, orderentit1_.orig_id as col_1_0_, orderentit1_.system_id as col_1_1_ 
from tExerep exerepenti0_
left outer join tOrder orderentit1_
on exerepenti0_.ORDER_ORIG_ID=orderentit1_.orig_id and exerepenti0_.SYSTEM_ID=orderentit1_.system_id
where
exerepenti0_.system_id=1 and orderentit1_.ORIG_ID='315905723'
or exerepenti0_.system_id=1 and orderentit1_.parent_orig_id='315905723'
or exerepenti0_.system_id=1 and orderentit1_.root_orig_id='315905723'

select exerepenti0_.orig_id as col_0_0_, exerepenti0_.system_id as col_0_1_, orderentit1_.orig_id as col_1_0_, orderentit1_.system_id as col_1_1_ 
from tExerep exerepenti0_
left outer join tOrder orderentit1_
on exerepenti0_.ORDER_ORIG_ID=orderentit1_.orig_id and exerepenti0_.SYSTEM_ID=orderentit1_.system_id
where
orderentit1_.system_id=1 and orderentit1_.ORIG_ID='315905723'
or orderentit1_.system_id=1 and orderentit1_.parent_orig_id='315905723'
or orderentit1_.system_id=1 and orderentit1_.root_orig_id='315905723'

мб я торможу (и надо больше спать и позже приходить на работу :grin: )
но нафик там outer если по условию (where) поля во второй таблице не могут быть одновременно null ?

zya369

а на счет почему второй быстрее - рискну предположить, что в нем условие на поля из одной таблицы (на полях индекс а в первом - на поля из разных => индекс не юзается... запросы имхо одинаковые из-за условий на поля из второй таблицы (если б их не было - были б разные)
ЗЫ сорри, если сказал что-то очевидно верное или очевидно неверное- см. поправку из предыдущего поста :grin:

pitrik2

но нафик там outer если по условию (where) поля во второй таблице не могут быть одновременно null ?
изначально было вот это:

where
exerepenti0_.system_id=1 and exerepenti0_.ORDER_ORIG_ID='315905723'
...

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

zya369

блин, ну так и писал бы полный SQL а не "для наглядности"
те запросы что в начальном посте возврю одинаковые результаты - и теже результаты будут если убрать left outer ...
а на счет использования индексов все равно все в силе - если в OR'ах используются колонки разных таблиц то мвидимо оракл не осиливает, что можно индекс юзать
ЗЫ напиши полные запросы - только без этих убогих названий колонок и таблиц :)

sinet

напиши полные запросы
и криейты на таблицы и индексы.

zya369

и криейты на таблицы

зачем? :shocked:
там вроде всего 2-3 поля юзаются и один индекс

sinet

Судя по первому посту, индексов как минимум два.

Werdna

первый запрос генерит hibernate и работает он намноооого дольше второго
А не надо использовать говно типа hibernate.
Все запросы надо писать руками и с пониманием.
Оставить комментарий
Имя или ник:
Комментарий: