Как переписать запрос без использования ОТДЕЛЬНОЙ функции в Oracle 12c

#sql #oracle #oracle12c #database-performance #query-performance

#sql #Oracle #oracle12c #база данных-производительность #запрос-производительность

Вопрос:

Как добиться того же результата без использования отдельной функции.
TAB_C = 2947109424 строки, act = 43460 строк

     SELECT tc.email_addr_id 
                                 , COUNT(DISTINCT tc.m_act_id) AS num_12mons 
                                 , COUNT(DISTINCT CASE WHEN ROUND(tc.outbound_date, 'DD')  
                                     > (ROUND(sysdate, 'DD') - 90) 
                                     THEN tc.m_act_id ELSE NULL END) AS num_3mons 
                                  , COUNT(DISTINCT CASE WHEN ROUND(tc.outbound_date, 'DD')  
                                      > (ROUND(sysdate, 'DD') - 180) 
                                      THEN tc.m_act_id ELSE NULL END) AS num_6mons 
                                  , COUNT(DISTINCT CASE WHEN ROUND(tc.outbound_date, 'DD')  
                                      > (ROUND(sysdate, 'DD') - 270) 
                                      THEN tc.m_act_id ELSE NULL END) AS num_9mons 
                             FROM Tab_C tc     
                             INNER JOIN act a 
                             ON tc.act_id = a.act_id 
                             where a.channel_code IN ('FM','RM') 
                                 AND ROUND(tc.outbound_date, 'DD') > (ROUND(sysdate, 'DD') - 365) 
                             GROUP BY tc.email_addr_id
 

Комментарии:

1. DISTINCT — замедляет выполнение запроса в рабочей среде

2. Вы использовали ROUND by DD. Если возможно, используйте прямой столбец там. Функция в столбце не позволит использовать индекс.

3. @Popeye , у нас есть индекс на основе функций для outbound_date, поэтому, если мы используем прямой столбец (без округления по dd), не пропустит ли это функциональный индекс??

4. О, если у вас есть функция index, вам следует использовать ROUND, чтобы получить выгоду от index

5. @Popeye, спасибо, но улучшения по-прежнему нет, есть ли какой-либо альтернативный способ, которым мы можем перепроектировать оператор DISTINCT CASE WHEN . Отчаянно ищу здесь какие-то данные.

Ответ №1:

Предполагается, что NULLIF выполняется намного быстрее, чем операторы CASE, и вы можете обнаружить, что именно CASE вызывает замедление, а не distinct … но это все из-за вашей индексации. Очевидно, что NULLIF работает только на основе поиска правильного значения, а не исключения «неправильных» значений, поэтому вам нужно отменить поиск.

это может работать лучше, но вам нужно будет перепроверить результаты.

 select email_addr_id,
    count(m_act_id) AS num_12mons,
    COUNT(nullif(sign(outbound_date  90 - ROUND(sysdate, 'DD')), -1))) AS num_3mons,
    COUNT(nullif(sign(outbound_date  180 - ROUND(sysdate, 'DD')), -1))) AS num_6mons,
    COUNT(nullif(sign(outbound_date  270 - ROUND(sysdate, 'DD')), -1))) AS num_9mons
from (
select distinct tc.email_addr_id, tc.m_act_id, round(tc.outbound_date, 'DD') as outbound_date
  from Tab_C tc     
  INNER JOIN act a ON tc.act_id = a.act_id 
  where a.channel_code IN ('FM','RM') 
    AND ROUND(tc.outbound_date, 'DD') > (ROUND(sysdate, 'DD') - 365))
group by email_addr_id;
 

Комментарии:

1. У нас есть индекс на Tab_C.act_id (условие соединения)

2. вы можете использовать дополнительные индексы в act.channel_code, поскольку вы фильтруете по нему, и вы можете захотеть создать индекс функции для вашего «Round (tab_c.outbound_date)»: medium.com/@bbrumm /…

3. созданный индекс функции в Round(tab_c.outbound_date), но без улучшения, попробует act.channel_code

4. JAD, я думаю, что столбец m_act_id отсутствует в num_3mons, num_6mons, num_9mons

5. нет, ему просто нужно количество, поэтому я сначала разделяю данные и обнуляю все, что не совпадает, чтобы получить количество… как я уже сказал, это может не сработать, ему нужно будет проверить выходные данные