Быстрее Postgres Подсчет с условием где - PullRequest
0 голосов
/ 29 апреля 2020

Мне нужно подсчитать общее количество строк в таблице с предложением where. Мое приложение может допустить некоторую неточность.

SELECT count(*) AS "count" FROM "Orders" AS "Order" WHERE "Order"."orderType" = 'online' AND "Order"."status" = 'paid';

Но, очевидно, это очень медленный запрос. Я наткнулся на этот ответ, но он возвращает количество всех строк в таблице.

Какой более быстрый метод подсчета, когда у меня есть предложение where? Я использую ORM в sequelize, поэтому любой соответствующий метод в sequelize также поможет.

Итак, EXPLAIN (ANALYZE, BUFFERS) SELECT count(*) AS "count" FROM "Orders" AS "Order" WHERE "Order"."orderType" = 'online' AND "Order"."status" != 'paid'; возвращает мне следующее:

Aggregate  (cost=47268.10..47268.11 rows=1 width=8) (actual time=719.722..719.723 rows=1 loops=1)
 Buffers: shared hit=32043
  ->  Seq Scan on ""Orders"" ""Order""  (cost=0.00..47044.35 rows=89501 width=0) (actual time=0.011..674.316 rows=194239 loops=1)
       Filter: (((status)::text <> 'paid'::text) AND ((""orderType"")::text = 'online'::text))
        Rows Removed by Filter: 830133
        Buffers: shared hit=32043
Planning time: 0.069 ms
Execution time: 719.755 ms

1 Ответ

0 голосов
/ 29 апреля 2020

Мое приложение может допускать некоторую неточность.

В PostgreSQL это довольно сложно использовать. Получить приблизительный ответ довольно легко, но сложно установить, насколько приблизительным является этот ответ. Всегда будут случаи, когда оценка может быть очень неправильной, и трудно понять, когда это происходит, не выполняя работу, необходимую для получения точного ответа.

В вашем плане запросов она отклоняется коэффициент 2,17. Это достаточно хорошо?

(стоимость = 0.00..47044.35 строк = 89501 ширина = 0) (фактическое время = 0.011.674.316 строк = 194239 циклов = 1)

Или, можете ли вы ограничить допустимую неточность в каком-то другом измерении? Что-то вроде «точный на какой-то момент за последний час»? При таком допуске вы можете создать материализованное представление для частичного суммирования данных, например:

create materialized view order_counts as 
    SELECT "orderType", "status", count(*) AS "count" FROM "Orders"
    group by 1,2;

, а затем вывести из этого подсчет с помощью предложения WHERE (и, возможно, пересчитать их). Эффективность этого зависит от того, сколько комбинаций "orderType" и "status" намного меньше, чем общее количество строк в основной таблице. Вам нужно будет настроить запланированное задание, чтобы периодически обновлять sh matview. Не реализовано PostgreSQL переписать ваш исходный запрос для использования matview, вы должны переписать его самостоятельно.

Вы показали нам два разных запроса, status = 'paid' и status != 'paid'. Является ли это ошибкой или они отражают различия в запросах, которые вы на самом деле хотите выполнить? Что еще может отличаться в этом пуле похожих запросов? Вы должны быть в состоянии ускорить использование индексов, но какой именно индекс будет зависеть от ваших запросов. Для запроса на равенство вы можете включить «статус» в индекс. Для запроса неравенства это не принесло бы пользы, поэтому вместо этого вы можете использовать частичный индекс WHERE status<>'paid'. (Но тогда этот индекс был бы бесполезен, если, например, слово «paid» было изменено на «delinquent».)

...