View Merging problem

vavan
Дата: 09.03.2011 17:17:09
допустим есть запрос или вьюха вида
select t.*,v.* from table1 t,view1 v where t.id=v.id(+)

view1 что-то вроде
select id,max(field1) aggvalue from table2 group by id

можно view1 как таковой и не использовать, вложенный запрос аналогичного типа написать прям внутри первого

суть претензий к ораклу :)
независимо от того выбираю ли я все поля из первого запроса или только поля из table1 он джойнит t с v. хотя должен по сути делать тупо select * from table1 во втором случае

здесь меня огорошили заявив что это неразрешимой сложности задача для оптимайзера

есть иные мнения? а еще лучше способы обойти корявое поведение? спасибо
брадобрей
Дата: 09.03.2011 17:26:20
Maxim Demenko вполне чОтко ответил
vavan
Дата: 09.03.2011 17:36:01
брадобрей
Maxim Demenko вполне чОтко ответил


с его _мнением_ я уже давно ознакомился
надеялся что здесь у когонть есть альтернативное восприятие проблемы
как по мне так никакой аццкой сложности в задаче вовсе нет и налицо явная недоработка товарищей. может можно хинтануть или еще как извернуться, есть у тебя конкретные идеи?
брадобрей
Дата: 09.03.2011 17:41:36
в общем случае нельзя пропустить джоин,
пример
with t1 as (select 1 id from dual) ,
      v as (select 1 id from dual union all
            select 1 id from dual union all
            select 1 id from dual)
select * from t1 left join v on t1.id = v.id

Твой случай сугубо частный, т.к. group by обеспечивает уни кальность.
А добавь в group by после id любое поле и какбэ сё, приехали.

Задача сложная, йа согласен.
vavan
Дата: 09.03.2011 17:48:16
брадобрей
в общем случае нельзя пропустить джоин,
Твой случай сугубо частный, т.к. group by обеспечивает уни кальность.
А добавь в group by после id любое поле и какбэ сё, приехали.


меня интересует не общий случай а именно мой "сугубо частный". и не твой, к-й тоже частный но совсем не повторяет мой
Репозиторий суппозиториев
Дата: 09.03.2011 17:57:17
Какое тут может быть альтернативное восприятие, если оптимизатор именно так работает?
vavan
Дата: 09.03.2011 18:20:03
Репозиторий суппозиториев
Какое тут может быть альтернативное восприятие, если оптимизатор именно так работает?


оптимизатору свойственно ошибаться
порой здорово помогают хинты и прочие переписывания запроса
может возможно и в этом случае помочь бедняге?
wurdu
Дата: 10.03.2011 03:41:00
vavan, то, что ты хочешь, называется Join Elimination. Oracle постепенно увеличивает кол-во случаев, когда оно применяется, но данный случай, похоже, еще не охвачен. Можно использовать scalar subquery:
SQL> select * from(
select t.*, (select max(field1) from t1 where t.id=t1.id) zz from table2 t
);
  2    3
Execution Plan
----------------------------------------------------------
Plan hash value: 1661637285

-----------------------------------------------------------------------------
| Id  | Operation          | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |        |   100 |  2600 |     2   (0)| 00:00:01 |
|   1 |  SORT AGGREGATE    |        |     1 |    26 |            |          |
|*  2 |   TABLE ACCESS FULL| T1     |     1 |    26 |     2   (0)| 00:00:01 |
|   3 |  TABLE ACCESS FULL | TABLE2 |   100 |  2600 |     2   (0)| 00:00:01 |
-----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("T1"."ID"=:B1)

SQL> select id, field1 from(
select t.*, (select max(field1) from t1 where t.id=t1.id) zz from table2 t
);
  2    3
Execution Plan
----------------------------------------------------------
Plan hash value: 1708808563

----------------------------------------------------------------------------
| Id  | Operation         | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |        |   100 |  2600 |     2   (0)| 00:00:01 |
|   1 |  TABLE ACCESS FULL| TABLE2 |   100 |  2600 |     2   (0)| 00:00:01 |
----------------------------------------------------------------------------

Но производительность может упасть (как и увеличиться).
vavan
Дата: 10.03.2011 10:39:38
wurdu
vavan, то, что ты хочешь, называется Join Elimination. Oracle постепенно увеличивает кол-во случаев, когда оно применяется, но данный случай, похоже, еще не охвачен. Можно использовать scalar subquery:
Но производительность может упасть (как и увеличиться).

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

select * from (select много_всего) v, (SELECT c.Account_Id SRAcc,
                 MAX (Spread_Remainder) SRMax,
                 SUM (Spread_Remainder) SpreadRemainder,
                 MIN (cs.Object_No)
                   KEEP (DENSE_RANK FIRST ORDER BY Spread_Remainder DESC)
                   SR,
                 MIN (c.Date_In)
                   KEEP (DENSE_RANK FIRST ORDER BY spread_remainder DESC)
                   SRDateIn,
                 MIN (cs.Spread_Volume)
                   KEEP (DENSE_RANK FIRST ORDER BY spread_remainder DESC)
                   SRVol,
                 MIN (cs.Spread_Cost)
                   KEEP (DENSE_RANK FIRST ORDER BY Spread_Remainder DESC)
                   SRCost
            FROM tcontractspread cs, tcontract c
           WHERE cs.object_no = c.object_no
                 AND SYSDATE BETWEEN c.Date_In AND c.Date_Out
          GROUP BY c.Account_Id) sr WHERE v.Acc = sr.SRAcc(+)
дак вот тут такое переписывание уже не кошерно делать казалось бы, т.к. породит кучу скалярных подзапросов. или это неизбежно?