Преимущество этого решения должно быть скорость. Он суммирует Table_demo в одну строку, что экономит потребность в вычисленном соединении для каждой используемой таблицы Table_demo.
SELECT
Last_Day_Report_Status,
DECODE(Last_Day_Report_Status, 'Complete', NVL(Completed,0), NVL(Total-Completed,0)) counts
FROM
(SELECT 'Complete' Last_Day_Report_Status FROM DUAL
UNION ALL
SELECT 'Incomplete' Last_Day_Report_Status FROM DUAL
)
OUTER APPLY
(SELECT COUNT(DECODE(processed,1,'Complete')) Completed, COUNT(1) Total
FROM Table_demo
WHERE run_datetime >= TRUNC(SYSDATE)-1
AND run_datetime < TRUNC(SYSDATE)
);
Большая проблема с этим оптимизатор отказывается обрабатывать COUNTS подзапрос первым или сделать как хеш-объединение, даже когда намекнул на смерть, в результате чего суммирования будет работать в два раза, комментарии приветствуются. Наиболее явная оптимизация запроса у меня есть (несмотря на уродливую подделкой присоединиться к 1 = 1), который, к сожалению, до сих пор вложенной-петли от союза к суммированию, является:
SELECT /*+ ordered */
Last_Day_Report_Status,
DECODE(Last_Day_Report_Status, 'Complete', NVL(Completed,0), NVL(Total-Completed,0)) counts
FROM
(SELECT COUNT(DECODE(processed,1,'Complete')) Completed, COUNT(1) Total
FROM Table_demo
WHERE run_datetime >= TRUNC(SYSDATE)-1
AND run_datetime < TRUNC(SYSDATE)
)
RIGHT OUTER JOIN
(SELECT 'Complete' Last_Day_Report_Status FROM DUAL
UNION ALL
SELECT 'Incomplete' Last_Day_Report_Status FROM DUAL
) ON 1=1;
Оптимизатор чувствовал себя неспособным использовать подсказка ORDERED
, которая запрашивает, что подзапросы выполняются в том порядке, в котором они записаны.
Учитывая путь оптимизации и при условии, что Table_demo может быть большим, суммирование может быть реализовано (предварительно консервировано). Процесс материализации имеет начальные затраты, поэтому может быть дорогостоящим в цикле, который выполняет 100 или 1000 раз в секунду. Несмотря на то, что запрос на материализованный запрос дважды запрашивается (один раз для каждой строки объединения), по-прежнему требуется недокументированный намек INLINE
ed, стандарт ROWNUM
в SELECT
, чтобы заставить это работать не будет, поскольку он знает, что только собирается быть одной строкой. Это дает хорошую оптимизацию:
WITH counts AS
(SELECT /*+ MATERIALIZE */ COUNT(DECODE(processed,1,'Complete')) Completed, COUNT(1) Total
FROM Table_demo
WHERE run_datetime >= TRUNC(SYSDATE)-1
AND run_datetime < TRUNC(SYSDATE)
)
SELECT
Last_Day_Report_Status,
DECODE(Last_Day_Report_Status, 'Complete', NVL(Completed,0), NVL(Total-Completed,0)) counts
FROM
(SELECT 'Complete' Last_Day_Report_Status FROM DUAL
UNION ALL
SELECT 'Incomplete' Last_Day_Report_Status FROM DUAL
)
OUTER APPLY
counts;
Версия оптимизатора, которую я использую, - это Oracle 12.1.0.1 SE. Я принял планы объяснения по номиналу, не проверяя трассировку выполнения.