2015-07-17 5 views
1

Я использую разработчик sql oracle. У меня есть одно сомнение и одна вещь, с которой у меня проблемы: 1) Мне нужно сделать выбор, который имеет некоторые правила.Улучшить выбор производительности и удобочитаемости

  • Этот выбор должен возвращать информацию из таблицы1.
  • Таблица2 является «ребенком» из таблицы1.
  • Дата от каждой таблицы должна быть от того же месяца/года текущего.
  • Идентификатор не должен быть ни в обеих таблицах.
  • В конечном возвращении должны быть только данные, которые из таблицы 1 должны быть только теми, что nrtable и nrgroupby находятся в подвыборке, который я сказал.

Если не было ясно, что я сделал одно, это работает, но это глупо, потому что я думаю, что есть способ сделать это, или более эффективным или более читаемым, потому что таким образом мне пришлось rewrit почти те же выберите два раза:

SELECT * 
    FROM TABLE1 
    WHERE NRSEQTABLE1 IN 
     (SELECT DECODE(T1.NRSEQTABLE1,NULL, T2.NRSEQTABLE1, T1.NRSEQTABLE1) AS NRSEQTABLE1 
     FROM 
     (SELECT NRSEQTABLE1, 
      NRNUM2 
     FROM TABLE1 T1 
     WHERE TO_CHAR(DTHRTABLE1, 'MM/YYYY') = TO_CHAR(SYSDATE, 'MM/YYYY') 
     AND IDRULE      = 'NO' 
     ) T1 
     FULL JOIN 
     (SELECT NRSEQTABLE1, 
      NRNUM2 
     FROM TABLE2 T2 
     WHERE TO_CHAR(DTHRTABLE2, 'MM/YYYY') = TO_CHAR(SYSDATE, 'MM/YYYY') 
     AND IDRULE      = 'NO' 
     ) T2 
     ON T2.NRSEQTABLE1 = T1.NRSEQTABLE1 
     AND T2.NRNUM2  = T1.NRNUM2 
    ) 
    AND NRGROUPBY IN 
     (SELECT NRGROUPBY 
     FROM TABLE1 
     WHERE NRSEQTABLE1 IN 
     (SELECT DECODE(T1.NRSEQTABLE1,NULL, T2.NRSEQTABLE1, T1.NRSEQTABLE1) AS NRSEQTABLE1 
     FROM 
      (SELECT NRSEQTABLE1, 
      NRNUM2 
      FROM TABLE1 T1 
      WHERE TO_CHAR(DTHRTABLE1, 'MM/YYYY') = TO_CHAR(SYSDATE, 'MM/YYYY') 
       AND IDRULE      = 'NO' 
     ) T1 
     FULL JOIN 
      (SELECT NRSEQTABLE1, 
      NRNUM2 
      FROM TABLE2 T2 
      WHERE TO_CHAR(DTHRTABLE2, 'MM/YYYY') = TO_CHAR(SYSDATE, 'MM/YYYY') 
      AND IDRULE      = 'NO' 
     ) T2 
     ON T2.NRSEQTABLE1 = T1.NRSEQTABLE1 
     AND T2.NRNUM2  = T1.NRNUM2 
     ) 
     GROUP BY TABLE1.NRGROUPBY 
     HAVING COUNT(TABLE1.NRSEQTABLE1) > 10 
    ) 
    ORDER BY NRGROUPBY, 
     NRSEQTABLE1; 

Извините за английский и спасибо за любую помощь

ответ

3

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

TO_CHAR(DTHRTABLE1, 'MM/YYYY') = TO_CHAR(SYSDATE, 'MM/YYYY') 

с

DTHRTABLE1 >= trunc(SYSDATE, 'MM') and DTHRTABLE1 < add_months(trunc(SYSDATE, 'MM'), 1) 

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

не требуется никакого полного соединения для вашей цели. Те

where id in (
     select id 
     from a 
      full join b using (id...) 
    ) 

являются worste способ сделать

where id in (
     select id 
     from a 
    ) 
    or id in (
     select id 
     from b 
    ) 

Второй подзапрос exsactily же, как и в первой части запроса, так что вы могли бы использовать подзапрос факторинга не оценить его дважды.Таким образом, вы можете переключить

select id1, id2, xyx 
from a 
where (
     id1 in (
      select id1 
      from a 
     ) 
     or id1 in (
      select id1 
      from b 
     ) 
    ) 
    and id2 in (
     select id2 
     from a 
     where (
       id1 in (
        select id1 
        from a 
       ) 
       or id1 in (
        select id1 
        from b 
       ) 
      ) 
     group by id2 
     having xyz2 
    ) 

в

with src as (
     select id1, id2, xyx 
     from a 
     where (
       id1 in (
        select id1 
        from a 
       ) 
       or id1 in (
        select id1 
        from b 
       ) 
      ) 
    ) 
select * 
from src 
where id2 in (
     select id2 
     from src 
     group by id2 
     having xyz 
    ) 

Но однажды самостоятельной группы присоединиться стали настолько явными вы можете переключить этот шаблон к аналитической эквивалентной ведьме быстрее, чем

select id1, id2, xyx 
from (
     select id1, id2, xyx, 
      COUNT(NRSEQTABLE1) over (partition by NRGROUPBY) as cnt 
     from a 
     where (
       id1 in (
        select id1 
        from a 
       ) 
       or id1 in (
        select id1 
        from b 
       ) 
      ) 
    ) 
where cnt > 10 

Если вы предоставите информацию о уникальности задействованных столбцов (особенно NRSEQTABLE1, NRNUM2 и NRGROUPBY), я мог бы предложить вам так мне, вероятно, лучший способ улучшить производительность, но в данный момент вы можете попробовать этот запрос:

select * 
from (
     SELECT t.*, 
      COUNT(NRSEQTABLE1) over (partition by NRGROUPBY) as cnt 
     FROM TABLE1 t 
     WHERE NRSEQTABLE1 IN (
       SELECT NRSEQTABLE1 
       FROM TABLE1 T1 
       WHERE DTHRTABLE1 >= trunc(SYSDATE, 'MM') and DTHRTABLE1 < add_months(trunc(SYSDATE, 'MM'), 1) 
        AND IDRULE = 'NO' 
      ) 
      OR NRSEQTABLE1 IN (
       SELECT NRSEQTABLE1 
       FROM TABLE2 T2 
       WHERE DTHRTABLE2 >= trunc(SYSDATE, 'MM') and DTHRTABLE2 < add_months(trunc(SYSDATE, 'MM'), 1) 
        AND IDRULE = 'NO' 
      ) 
    ) 
where cnt > 10 

UPDATE

Учитывая, что «NRSEQTABLE1 является уникальным Pk из table1, но в table2 это Аппарат FK»

первый подзапрос может быть бесполезным, поскольку эти строки, где TABLE1

NRSEQTABLE1 IN (
     SELECT NRSEQTABLE1 
     FROM TABLE1 T1 
     WHERE DTHRTABLE1 >= trunc(SYSDATE, 'MM') and DTHRTABLE1 < add_months(trunc(SYSDATE, 'MM'), 1) 
      AND IDRULE = 'NO' 
    ) 

являются именно те из них, где

DTHRTABLE1 >= trunc(SYSDATE, 'MM') and DTHRTABLE1 < add_months(trunc(SYSDATE, 'MM'), 1) 
    AND IDRULE = 'NO' 

Тогда ваш запрос будет быть

select * 
from (
     SELECT t.*, 
      COUNT(NRSEQTABLE1) over (partition by NRGROUPBY) as cnt 
     FROM TABLE1 t 
     WHERE (
       DTHRTABLE1 >= trunc(SYSDATE, 'MM') and DTHRTABLE1 < add_months(trunc(SYSDATE, 'MM'), 1) 
       AND IDRULE = 'NO' 
      ) 
      OR NRSEQTABLE1 IN (
       SELECT NRSEQTABLE1 
       FROM TABLE2 T2 
       WHERE DTHRTABLE2 >= trunc(SYSDATE, 'MM') and DTHRTABLE2 < add_months(trunc(SYSDATE, 'MM'), 1) 
        AND IDRULE = 'NO' 
      ) 
    ) 
where cnt > 10 

Чтение более внимательно на ваш вопрос, где я заметил, что ты сказал «idrule не должно быть в обеих таблицах» , но этот запрос (так, следовательно, и исходный) не подходит для этой цели, потому что он проверяет, является ли «idrule равным« NO »хотя бы один раз в любой из таблиц TABLE1 и TABLE2».

+0

для 'id in (две таблицы)', почему бы не использовать 'union'? –

+0

Использование союза вместо него не всегда лучше, но оно также может быть. В основном это зависит от мощности данных, от избирательности задействованных столбцов и наличия на них полезных индексов. Я также думаю, что первый подзапрос бесполезен, если NRSEQTABLE1 уникален, но подробности об этом отсутствуют. –

+0

Я просто понял, что если OP ищет «COUNT (NRSEQTABLE1)> 10», этот столбец не уникален и что он встречается много раз. Таким образом, первый подзапрос не бесполезен, и использование UNION может быть лучше, если нет индексов в столбце NRSEQTABLE1 для обеих таблиц. –

1

Вы можете использовать пункт WITH, также известный в CTE. Было бы это:

with t1 as 
    (SELECT NRSEQTABLE1, NRNUM2 
    FROM TABLE1 T1 
    WHERE TO_CHAR(DTHRTABLE1, 'MM/YYYY') = TO_CHAR(SYSDATE, 'MM/YYYY') 
    AND IDRULE = 'NO'), 
t2 as 
    (SELECT NRSEQTABLE1, NRNUM2 
     FROM TABLE2 T2 
     WHERE TO_CHAR(DTHRTABLE2, 'MM/YYYY') = TO_CHAR(SYSDATE, 'MM/YYYY') 
     AND IDRULE = 'NO'), 
t3 as 
    (select DECODE(T1.NRSEQTABLE1,NULL, T2.NRSEQTABLE1, T1.NRSEQTABLE1) AS NRSEQTABLE1 
    from T1 FULL JOIN T2 
     ON T2.NRSEQTABLE1 = T1.NRSEQTABLE1 
     AND T2.NRNUM2  = T1.NRNUM2), 
t4 as 
    (SELECT NRGROUPBY 
     FROM TABLE1 
     WHERE NRSEQTABLE1 IN 
     (select NRSEQTABLE1 from t3) 
     GROUP BY TABLE1.NRGROUPBY 
     HAVING COUNT(TABLE1.NRSEQTABLE1) > 10) 
SELECT * 
FROM TABLE1 
WHERE NRSEQTABLE1 IN (select NRSEQTABLE1 from t3)    
    AND NRGROUPBY IN (select NRGROUPBY from t4)  
ORDER BY NRGROUPBY, NRSEQTABLE1; 

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

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