Я бы постарался не использовать UNION ALL
заявления, если вы можете помочь. Один из способов обойти это - создать таблицу измерений календаря.
CREATE TABLE cal_date_dim
(
id INT,
cal_date DATE,
cal_date_year INT,
date_range_id INT
)
ORDER BY cal_date
UNSEGMENTED ALL NODES;
INSERT INTO cal_date_dim (id, cal_date, cal_date_year, date_range_id) VALUES (DAYS('2003-10-20'), '2003-10-20', YEAR('2003-10-20'::DATE), 0);
/* Run this 6000 times, or as many times as is needed to populate the table */
INSERT INTO cal_date_dim (id, cal_date, cal_date_year, date_range_id)
SELECT DAYS(next_date), next_date, YEAR(next_date), 0
FROM (
SELECT MAX(cal_date) + 1 next_date
FROM cal_date_dim
) n;
UPDATE cal_date_dim SET date_range_id = 1 WHERE cal_date >= '2003-10-23' and cal_date < '2007-01-01';
UPDATE cal_date_dim SET date_range_id = 2 WHERE cal_date >= '2007-01-01' and cal_date < '2010-04-03';
UPDATE cal_date_dim SET date_range_id = 3 WHERE cal_date >= '2010-04-03' and cal_date < '2013-07-02';
UPDATE cal_date_dim SET date_range_id = 4 WHERE cal_date >= '2013-07-02' and cal_date < '2016-10-01';
UPDATE cal_date_dim SET date_range_id = 5 WHERE cal_date >= '2016-10-01' and cal_date <= '2019-12-10';
В приведенном выше блоке кода я создал общую таблицу измерений календаря. Вы можете создать больше столбцов, таких как cal_date_month
, cal_date_quarter
, cal_date_day
и т. Д., Если хотите расширить эту логику.
Чтобы заполнить таблицу, я запустил один оператор INSERT
сзначение статической даты, затем я выполнил второй оператор INSERT
около 6000 раз, чтобы убедиться, что все даты покрыты.
Затем я обновил столбец date_range_id
на основе значений, которые вы пытаетесь сгруппировать.
С этой таблицей измерений теперь можно присоединить таблицу table_data
к новой таблице измерений календаря cal_date_dim
с помощью следующего запроса:
SELECT value
FROM (
SELECT c.date_range_id, COUNT(a_date) value
FROM
table_data t
LEFT JOIN cal_date_dim c
ON t.a_date = c.cal_date
WHERE c.date_range_id > 0
GROUP BY c.date_range_id
) x;
Это будетвозвращает тот же результат, что и ваш запрос UNION ALL
, приведенный выше, и должен быть более производительным.
Если диапазоны дат, которые вы указали выше, не являются статичными, но всегда меняются, вы все равно можете повысить производительность, создав *Таблица 1026 * в любом случае, но укажите date_range_id
с CASE
операторами.
SELECT cal_date, CASE WHEN cal_date >= '2019-12-11' and a_date < '2020-02-03' THEN 1 WHEN ... END as date_range_id
FROM cal_date_dim
Присоединение таблицы table_data
к приведенному выше в качестве подзапроса может все же быть более производительным, чем выполнение нескольких операторов UNION ALL
,даже если date_range_id
вычисляется динамически.
ПРИМЕЧАНИЕ: Обратите внимание, что суперпроекция таблицы cal_date_dim
отсортирована по cal_date
. Поскольку вы присоединяете cal_date
к table_data.a_date
, приведенный выше запрос будет выполняться значительно быстрее, если вы создадите проекцию для таблицы table_data
, в которой a_date
является первым столбцом ORDER BY
. Чтобы еще больше оптимизировать запрос, рассмотрите возможность сегментации по a_date
.
CREATE PROJECTION table_data_date_sorted
(
a_date,
...
)
AS
SELECT
a_date,
...
FROM table_data
ORDER BY
a_date,
...
SEGMENTED BY HASH(a_date) ALL NODES;