#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. нет, ему просто нужно количество, поэтому я сначала разделяю данные и обнуляю все, что не совпадает, чтобы получить количество… как я уже сказал, это может не сработать, ему нужно будет проверить выходные данные