Как оптимизировать объединение всех операторов - PullRequest
0 голосов
/ 10 октября 2019

Я хочу, чтобы результат диапазона отображался на графике. Я подготовил следующий запрос: (для vertica)

select count(a_date) as value FROM table_data where a_date >= '2003-10-23' and a_date < '2007-01-01' union all select count(a_date) as value FROM table_data where a_date >= '2007-01-01' and a_date < '2010-04-03' union all select count(a_date) as value FROM table_data where a_date >= '2010-04-03' and a_date < '2013-07-02' union all select count(a_date) as value FROM table_data where a_date >= '2013-07-02' and a_date < '2016-10-01' union all select count(a_date) as value FROM table_data where a_date >= '2016-10-01' and a_date <= '12-10-2019'

Это занимает много времени, так как table_data содержит огромные записи.

Есть ли быстрый способ

1 Ответ

3 голосов
/ 11 октября 2019

Я бы постарался не использовать 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;
...