Oracle8i Enterprise Edition Release 8.1.7.4.1 - Production
Нужно сделать следующее: Есть базовый набор данных, это либо простая таблица, либо результат некоторого запроса. Помимо него есть таблица - фильтр, по структуре она представляет набор полей из основной. В нее заносятся правила фильтрации - значения некоторых полей в базовой таблице. Результатом должны стать все записи основной таблицы, которые не попадают ни под один фильтр.
таблица - фильтр :
id_acct NUMBER(15,0),
nacct VARCHAR2(9),
id_service NUMBER(5,0),
id_provider NUMBER(4,0),
subservice NUMBER(9,0),
в ней возможны следующие варианты записей :
-- Id_Acct |NAcct | Id_Service | Id_Provider | SubService
-- -----------------------------------------------------
--1 V | V | V | V | V
--2 V | V | | V |
--3 V | V | V | |
--4 V | V | | |
--5 | | V | V | V
--6 | | | V |
--7 | | V | |
(V означает какое то значение. пусто значит NULL)
каждое правило означает отбросить все записи основной таблицы где соответствующее поле равно заданному. Правило 1 означает отбросить по точному соответствию всех полей, правило 2 - по соответствию полей id_acct и Id_Provider, правило №6 - по Id_Service и т.д.
В качестве базовой таблицы используется результат подзапроса. (~2,5 млн строк)
В таблице фильтра ~100 тыс строк
Я пробовал два варианта (одинаково хреново работающих), ничего другого на ум не приходит.
вариант №1 - внешнее соединение с таблицей фильтров 7 раз (по одному на каждый тип условия):
SQL Statement from editor:
select /*+ ordered use_nl(a, ss) use_nl(EEF1, EEF2, EEF3, EEF4, EEF5, EEF6, EEF7)
index(EEF1 EEF_NACCT_SUBSERVICE)
index(EEF2 EEF_NACCT_ID_PROVIDER)
index(EEF3 EEF_NACCT_ID_SERVICE)
index(EEF4 EEF_NACCT)
index(EEF5 EEF_SUBSERVICE)
index(EEF6 EEF_ID_PROVIDER)
index(EEF7 EEF_ID_SERVICE)*/*
from --kp.erkc_vc_zkh_saldo@erkc a,
Mihsv.erkc_vc_zkh_saldo a,
ServiceState ss,
(select * from ExchangeExcludeFilter where IsClose = 0 and nAcct is not null and subService is not null) EEF1, -- nacct-subservice
(select * from ExchangeExcludeFilter where IsClose = 0 and nAcct is not null and id_provider is not null and id_service is null) EEF2, -- nacct-id_provider
(select * from ExchangeExcludeFilter where IsClose = 0 and nAcct is not null and id_provider is null and id_service is not null) EEF3, -- nacct-id_service
(select * from ExchangeExcludeFilter where IsClose = 0 and nAcct is not null and id_provider is null and id_service is null) EEF4, -- nacct
(select * from ExchangeExcludeFilter where IsClose = 0 and nAcct is null and subservice is not null) EEF5, -- subservice
(select * from ExchangeExcludeFilter where IsClose = 0 and nAcct is null and id_provider is not null and id_service is null) EEF6, -- id_provider_id_service
(select * from ExchangeExcludeFilter where IsClose = 0 and nAcct is null and id_provider is null and id_service is not null) EEF7 -- id_service
where a.acc_pu = ss.nacct
and (a.sub_srv_pu = ss.subservice)
and ( a.saldo != ss.balans
or a.fio != upper (ss.fio)) -- óñëîâèÿ ôèëüòðà
and EEF1.NAcct (+) = SS.NAcct
and EEF1.SubService (+) = SS.Subservice
and EEF1.NAcct is null
and EEF1.SubService is null
and EEF2.NAcct (+) = SS.NAcct
and EEF2.id_provider (+) = to_number (substr (ss.subservice, -3, 3))
and EEF2.NAcct is null
and EEF2.Id_Provider is null
and EEF3.NAcct (+) = SS.NAcct
and EEF3.id_service (+) = to_number (substr (ss.subservice, 1, length (ss.subservice) - 3))
and EEF3.NAcct is null
and EEF3.Id_Service is null
and EEF4.NAcct (+) = SS.NAcct
and EEF4.NAcct is null
and EEF5.SubService (+) = SS.SubService
and EEF5.SubService is null
and EEF6.id_provider (+) = to_number (substr (ss.subservice, -3, 3))
and EEF6.Id_Provider is null
and EEF7.id_service (+) = to_number (substr (ss.subservice, 1, length (ss.subservice) - 3))
and EEF7.id_service is null
------------------------------------------------------------
Statement Id=4203132 Type=
Cost=2,64039087471493E-308 TimeStamp=01-06-06::13::29:27
(1) SELECT STATEMENT RULE
Est. Rows: 396 Cost: 10 527
FILTER
(32) NESTED LOOPS OUTER
(29) FILTER
(28) NESTED LOOPS OUTER
(25) FILTER
(24) NESTED LOOPS OUTER
(21) FILTER
(20) NESTED LOOPS OUTER
(17) FILTER
(16) NESTED LOOPS OUTER
(13) FILTER
(12) NESTED LOOPS OUTER
(9) FILTER
(8) NESTED LOOPS OUTER
(5) NESTED LOOPS
Est. Rows: 396 Cost: 4 587
(2) TABLE ACCESS FULL MIHSV.ERKC_VC_ZKH_SALDO [Not Analyzed]
(2) Est. Rows: 2 000 Cost: 2 587
Tablespace: USERS
(4) TABLE ACCESS BY INDEX ROWID CITY.SERVICESTATE [Not Analyzed]
(4) Est. Rows: 2 000 Cost: 1
Tablespace: CITY
(3) UNIQUE INDEX UNIQUE SCAN CITY.SERVICESTATE#NEW_PK [Not Analyzed]
Est. Rows: 2 000
(7) TABLE ACCESS BY INDEX ROWID CITY.EXCHANGEEXCLUDEFILTER [Not Analyzed]
Est. Rows: 1 Cost: 2
(6) NON-UNIQUE INDEX RANGE SCAN CITY.EEF_NACCT_SUBSERVICE [Not Analyzed]
Est. Rows: 1 Cost: 1
(11) TABLE ACCESS BY INDEX ROWID CITY.EXCHANGEEXCLUDEFILTER [Not Analyzed]
Est. Rows: 1 Cost: 2
(10) NON-UNIQUE INDEX RANGE SCAN CITY.EEF_NACCT_ID_PROVIDER [Not Analyzed]
Est. Rows: 1 Cost: 1
(15) TABLE ACCESS BY INDEX ROWID CITY.EXCHANGEEXCLUDEFILTER [Not Analyzed]
Est. Rows: 1 Cost: 2
(14) NON-UNIQUE INDEX RANGE SCAN CITY.EEF_NACCT_ID_SERVICE [Not Analyzed]
Est. Rows: 1 Cost: 1
(19) TABLE ACCESS BY INDEX ROWID CITY.EXCHANGEEXCLUDEFILTER [Not Analyzed]
Est. Rows: 1 Cost: 2
(18) NON-UNIQUE INDEX RANGE SCAN CITY.EEF_NACCT [Not Analyzed]
Est. Rows: 1 Cost: 1
(23) TABLE ACCESS BY INDEX ROWID CITY.EXCHANGEEXCLUDEFILTER [Not Analyzed]
Est. Rows: 1 Cost: 2
(22) NON-UNIQUE INDEX RANGE SCAN CITY.EEF_SUBSERVICE [Not Analyzed]
Est. Rows: 1 Cost: 1
(27) TABLE ACCESS BY INDEX ROWID CITY.EXCHANGEEXCLUDEFILTER [Not Analyzed]
Est. Rows: 1 Cost: 3
(26) NON-UNIQUE INDEX RANGE SCAN CITY.EEF_ALL [Not Analyzed]
Est. Rows: 1 Cost: 2
(31) TABLE ACCESS BY INDEX ROWID CITY.EXCHANGEEXCLUDEFILTER [Not Analyzed]
Est. Rows: 1 Cost: 2
(30) NON-UNIQUE INDEX RANGE SCAN CITY.EEF_ID_SERVICE [Not Analyzed]
Est. Rows: 1 Cost: 1
[/SRC][FIXED][/FIXED]
он хорошо работает когда в фильтрах сотни записей, на сотнях тыс. понятно умирает...
Вариант второй - это внешнее сединение через NVL ():
SQL Statement from editor:
select /*+ ordered use_nl(a, ss)*/*
from
ExchangeExcludeFilter EEF,
(select * from Mihsv.erkc_vc_zkh_saldo) a,
ServiceState ss
where a.acc_pu = ss.nacct
and (a.sub_srv_pu = ss.subservice)
and ( a.saldo != ss.balans
or a.fio != upper (ss.fio))
and nvl(EEF.NAcct (+),ss.NAcct) = SS.NAcct
and nvl(EEF.SubService (+),SS.Subservice) = SS.Subservice
and nvl(EEF.id_service (+),to_number (substr (ss.subservice, 1, length (ss.subservice) - 3))) = to_number (substr (ss.subservice, 1, length (ss.subservice) - 3))
and nvl(EEF.id_provider (+),to_number (substr (ss.subservice, -3, 3))) = to_number (substr (ss.subservice, -3, 3))
and EEF.NAcct is null
and EEF.SubService is null
and EEF.Id_Service is null
and EEF.Id_provider is null
------------------------------------------------------------
Statement Id=11072 Type=
Cost=2,64039087471493E-308 TimeStamp=01-06-06::13::34:14
(1) SELECT STATEMENT RULE
Est. Rows: 396 Cost: 8 547
FILTER
(7) NESTED LOOPS OUTER
(5) NESTED LOOPS
Est. Rows: 396 Cost: 4 587
(2) TABLE ACCESS FULL MIHSV.ERKC_VC_ZKH_SALDO [Not Analyzed]
(2) Est. Rows: 2 000 Cost: 2 587
Tablespace: USERS
(4) TABLE ACCESS BY INDEX ROWID CITY.SERVICESTATE [Not Analyzed]
(4) Est. Rows: 2 000 Cost: 1
Tablespace: CITY
(3) UNIQUE INDEX UNIQUE SCAN CITY.SERVICESTATE#NEW_PK [Not Analyzed]
Est. Rows: 2 000
(6) TABLE ACCESS FULL CITY.EXCHANGEEXCLUDEFILTER [Not Analyzed]
Est. Rows: 2 000 Cost: 10
но там на последнем шаге access full к таблице фильтров. ТОже никуда не годится ...
Как я понимаю. при аткой постановке запроса, индекс заставить использовать его нелься в принципе ?
пытался применить во втором варианте вместо NL MERGE JOIN но оптимизатор игнорирует хинт USE_MERGE для таблицы фильтров :
[SRC oracle] SQL Statement from editor:
select /*+ ordered use_merge(a, ss,EEF)*/*
from
ExchangeExcludeFilter EEF,
(select * from Mihsv.erkc_vc_zkh_saldo) a,
ServiceState ss
where a.acc_pu = ss.nacct
and (a.sub_srv_pu = ss.subservice)
and ( a.saldo != ss.balans
or a.fio != upper (ss.fio))
and nvl(EEF.NAcct (+),ss.NAcct) = SS.NAcct
and nvl(EEF.SubService (+),SS.Subservice) = SS.Subservice
and nvl(EEF.id_service (+),to_number (substr (ss.subservice, 1, length (ss.subservice) - 3))) = to_number (substr (ss.subservice, 1, length (ss.subservice) - 3))
and nvl(EEF.id_provider (+),to_number (substr (ss.subservice, -3, 3))) = to_number (substr (ss.subservice, -3, 3))
and EEF.NAcct is null
and EEF.SubService is null
and EEF.Id_Service is null
and EEF.Id_provider is null
------------------------------------------------------------
Statement Id=9588 Type=
Cost=2,64039087471493E-308 TimeStamp=01-06-06::13::36:03
(1) SELECT STATEMENT RULE
Est. Rows: 396 Cost: 8 423
FILTER
(9) NESTED LOOPS OUTER
(7) MERGE JOIN
Est. Rows: 396 Cost: 4 463
(3) SORT JOIN
Est. Rows: 2 000 Cost: 2 647
(2) TABLE ACCESS FULL MIHSV.ERKC_VC_ZKH_SALDO [Not Analyzed]
(2) Est. Rows: 2 000 Cost: 2 587
Tablespace: USERS
(6) FILTER
(5) SORT JOIN
(4) TABLE ACCESS FULL CITY.SERVICESTATE [Not Analyzed]
(4) Est. Rows: 2 000 Cost: 1 728
Tablespace: CITY
(8) TABLE ACCESS FULL CITY.EXCHANGEEXCLUDEFILTER [Not Analyzed]
(8) Est. Rows: 2 000 Cost: 10
Tablespace: CITY
Помогите! третий день пухну... :(