переписать запрос с заменой не в - PullRequest
0 голосов
/ 20 ноября 2018

Я хочу переписать приведенный ниже запрос таким образом, чтобы удалить NOT IN это возможно?

select * from TRX_T TT, TRX_SUB TS
where TT.CODE=TS.CODE
and TT.SUBID= TS.ID
and TS.VALUE=1
and TS.CODE=1
AND TS.ID=17
AND TT.STATUS NOT IN('T','R','C')

Если бы статус был IN, я бы тогда использовал union all

Причина, по которой я хочу переписать, потому что ниже рекомендация оракула.

Предикат "TT". "STATUS" <> 'C', используемый в строке ID 5 выполнения план содержит выражение в индексированном столбце "STATUS" это выражение мешает оптимизатору эффективно использовать индексы на стол TT.

Количество различных значений

    T       264
    C   5489709
    D      2987
    J       924
    L    529430
    R     39382
    S      5449

Индекс TRX_T выглядит следующим образом: (CODE,SUBID,TYPE,STATUS,NO_SL)

Ответы [ 5 ]

0 голосов
/ 20 ноября 2018

Попробуйте ниже, вы можете использовать «кроме»:

SELECT * 
FROM   trx_t TT, 
       trx_sub TS 
WHERE  TT.code = TS.code 
       AND TT.subid = TS.id 
       AND TS.value = 1 
       AND TS.code = 1 
       AND TS.id = 17 
EXCEPT 
SELECT * 
FROM   trx_t TT, 
       trx_sub TS 
WHERE  TT.status = 'T' 
        OR TT.status = 'R' 
        OR TT.status = 'C' 
0 голосов
/ 20 ноября 2018

Если вы хотите настроить запрос, вы должны понимать свою модель данных и свои данные.Оптимизатор говорит, что не может эффективно использовать индекс для TRX_T.Давайте посмотрим на этот составной индекс:

  • CODE: используется в критериях объединения
  • SUBID: используется в критериях соединения
  • TYPE: не используется
  • STATUS: можно использовать в качестве фильтра?
  • NO_SL: не используется

В вашем запросе используются три из пяти проиндексированных столбцов.Но поскольку в STATUS есть выражение NOT IN, оптимизатор не использует индекс для оценки фильтра.Таким образом, он читает каждую запись в TRX_T, которая соответствует записи в TRX_SUB, и оценивает фильтр в таблице.

Возможно, если вы положительно выразили условие как TT.STATUS IN ('D','J','L', 'S'), тогда оптимизатор сможет использовать SKIP SCAN для оценки фильтра по индексу.

Однако использование индекса было бы более эффективным, если бы TRX_T.TYPE использовался в качестве фильтра (или если порядок столбцов индекса был перестроен так, чтобы иметь STATUS до TYPE, но несделать это, так как это может дестабилизировать другие запросы).

Другой вариант - переписать выражение как подзапрос NOT IN (если у вас есть no нулевые значения в (TRX_T.CODE, TRX_T.SUBID), иначе как подзапрос NOT EXISTS):

select * from TRX_T TT, TRX_SUB TS
where TT.CODE=TS.CODE
and TT.SUBID= TS.ID
and TS.VALUE=1
and TS.CODE=1
AND TS.ID=17
AND (TT.CODE, TT.SUBID) NOT IN
     (select x.CODE, x.SUBID
      from trx_t x
      where x.status in ('T','R','C')
     )

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

Обратите внимание, что применяются обычные оговорки.Настройка запросов на StackOverflow - игра в кружки.Слишком много информации отсутствует (объемы данных, перекос, другие индексы, планы объяснения и т. Д.), Чтобы мы могли делать что-то кроме догадок.

0 голосов
/ 20 ноября 2018

Вы можете попробовать использовать left join и отфильтровать TT2.status is null, чтобы получить те записи, которые not in ('T','R','C')

select * from TRX_T TT
   join  TRX_SUB TS on  TT.CODE=TS.CODE and TT.SUBID= TS.ID
   left join (select * from TRX_T where STATUS in ('T','R','C')) TT2 on 
   TT.CODE=TT2.CODE and TT.SUBID= TT2.SUBID
where TS.VALUE=1 and TS.CODE=1 AND TS.ID=17 and TT2.status is null
0 голосов
/ 20 ноября 2018

Вы можете использовать minus оператор набора как

select *
  from TRX_T TT
  join TRX_SUB TS
    on ( TT.CODE = TS.CODE
     and TT.SUBID = TS.ID )
 where TS.VALUE = 1
   and TS.CODE = 1
   and TS.ID = 17
minus
select *
  from TRX_T TT
  join TRX_SUB TS
    on ( TT.CODE = TS.CODE
     and TT.SUBID = TS.ID )
 where TS.VALUE = 1
   and TS.CODE = 1
   and TS.ID = 17
   and TT.STATUS in ('T', 'R', 'C');

PS Да, Not in в основном проблематично с точки зрения производительности, и как сторона, не использующая nvlфункция не должна быть забыта при использовании Not in.

0 голосов
/ 20 ноября 2018

использовать явное соединение и не может быть заменено следующим способом

   select * from TRX_T TT
   join  TRX_SUB TS
    on  TT.CODE=TS.CODE and TT.SUBID= TS.ID
    where TS.VALUE=1
    and TS.CODE=1
    AND TS.ID=17 
    and not exists
    ( select 1 from TRX_T t1 where t1.CODE=TT.code
     and (t1.STATUS ='T' OR t1.STATUS='R' or t1.STATUS='C')
    )
...