Как ускорить SUM-запрос в postgres на большой таблице - PullRequest
0 голосов
/ 04 ноября 2019

Проблема

Я пытаюсь выполнить следующий запрос для представления SQL в базе данных postgres:

SELECT sum(value) FROM invoices_view;

invoices_view содержит приблизительно 45 миллионов строк, размер данных всей базы данных составляет 40,5 ГБ, а база данных имеет 61 ГБ ОЗУ.

В настоящее время этот запрос занимает 4,5 секунды, и я бы хотел, чтобыв идеале - менее 1 секунды.

То, что я пробовал

Конечно, я не могу добавлять индексы непосредственно в представление SQL, но у меня есть индекс в базовой таблице:

CREATE INDEX invoices_on_value_idx ON invoices (value);

Я также запустил VACUUM ANALYZE в таблице счетов.

ОБЪЯСНИТЬ АНАЛИЗ

Выходиз EXPLAIN ANALYZE выглядит следующим образом:

EXPLAIN (ANALYZE, BUFFERS) SELECT sum(value) FROM invoices_view;
Finalize Aggregate  (cost=1514195.47..1514195.47 rows=1 width=32) (actual time=5102.805..5102.806 rows=1 loops=1)
  Buffers: shared hit=14996 read=1446679
  I/O Timings: read=3235.147
  ->  Gather  (cost=1514195.16..1514195.47 rows=3 width=32) (actual time=5102.716..5109.229 rows=4 loops=1)
        Workers Planned: 3
        Workers Launched: 3
        Buffers: shared hit=14996 read=1446679
        I/O Timings: read=3235.147
        ->  Partial Aggregate  (cost=1513195.16..1513195.17 rows=1 width=32) (actual time=5097.626..5097.626 rows=1 loops=4)
              Buffers: shared hit=14996 read=1446679
              I/O Timings: read=3235.147
              ->  Parallel Seq Scan on invoices  (cost=0.00..1505835.14 rows=14720046 width=6) (actual time=0.049..3734.495 rows=11408036 loops=4)
                    Buffers: shared hit=14996 read=1446679
                    I/O Timings: read=3235.147
Planning Time: 2.503 ms
Execution Time: 5109.327 ms

Есть ли у кого-нибудь мысли о том, как я мог бы ускорить это? Или я должен искать альтернативы postgres на этом этапе?

Подробнее

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

Например, мне нужно иметь возможность суммировать на основе вводимых пользователем данных, т.е. дополнительных предложений WHERE и GROUP BY.

Сохранение промежуточного итога решит проблему только для этого простейшего случая.

Ответы [ 2 ]

0 голосов
/ 04 ноября 2019

Вы должны рассмотреть возможность использования триггера для отслеживания скользящей суммы:

CREATE OR REPLACE FUNCTION func_sum_invoice()
RETURNS trigger AS
$BODY$
BEGIN
    UPDATE invoices_sum
    SET total = total + NEW.value;
RETURN NEW;
END;
$BODY$

Затем создайте триггер, используя эту функцию:

CREATE TRIGGER sum_invoice
AFTER INSERT ON invoices
FOR EACH ROW
EXECUTE PROCEDURE func_sum_invoice();

Теперь каждая вставка в invoices таблица сработает триггер, который подсчитывает скользящую сумму. Чтобы получить эту сумму, теперь вам нужен только один выбор, который должен быть очень быстрым:

SELECT total
FROM invoices_sum;
0 голосов
/ 04 ноября 2019

Если ваша таблица только для вставки, есть способы получить ваши суммы (намного) быстрее.

Предполагая, что есть столбец с монотонно увеличивающимися значениями (например, id или созданный в вашем примере), создайте МАТЕРИАЛИЗОВАННЫЙ ВИД для предварительного вычисления сумм старше (недавнего) заданного порога. А затем просто добавьте сумму последних добавлений к нему.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...