Postgresql производительность - PullRequest
0 голосов
/ 27 февраля 2020

Я выполняю запрос подсчета для таблицы postgresql. Название таблицы - симкарты, содержащие поля id, card_state и еще 10. Simcards содержит около 13 миллионов записей

Мой запрос

SELECT CAST(count(*) AS INT) FROM simcards WHERE card_state = 'ACTIVATED';

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

CREATE INDEX activated_count on simcards (card_state) where card_state = 'ACTIVATED';

Но без улучшений. Я думаю, это потому, что я получил более 12 миллионов записей с card_state = 'ACTIVATED'. Обратите внимание, что card_state может быть 'ACTIVATED', 'PREPROVISIONED', 'TERMINATED'

Кто-нибудь получил представление о том, как можно существенно улучшить счет?

Запуск EXPLAIN (ANALYZE, BUFFERS) SELECT CAST(count(*) AS INT) FROM simcards WHERE card_state = 'ACTIVATED'; дает

Finalize Aggregate  (cost=540300.95..540300.96 rows=1 width=4) (actual time=7103.814..7103.814 rows=1 loops=1)
  Buffers: shared hit=2295 read=155298
  ->  Gather  (cost=540300.74..540300.95 rows=2 width=8) (actual time=7103.773..7103.810 rows=3 loops=1)
        Workers Planned: 2
        Workers Launched: 2
        Buffers: shared hit=2295 read=155298
        ->  Partial Aggregate  (cost=539300.74..539300.75 rows=1 width=8) (actual time=7006.368..7006.368 rows=1 loops=3)
              Buffers: shared hit=5983 read=455025
              ->  Parallel Seq Scan on simcards  (cost=0.00..526282.77 rows=5207186 width=0) (actual time=2.677..6483.503 rows=4166620 loops=3)
                    Filter: (card_state = 'ACTIVATED'::text)
                    Rows Removed by Filter: 10965
                    Buffers: shared hit=5983 read=455025
Planning time: 0.333 ms
Execution time: 7123.739 ms

Ответы [ 2 ]

2 голосов
/ 27 февраля 2020

Подсчет идет медленно. Вот несколько идей, как его улучшить:

  1. Если вам не нужны точные результаты, используйте оценки PostgreSQL:

    /* this will improve the results */
    ANALYZE simcards;
    
    SELECT t.reltuples * freqs.freq AS count
    FROM pg_class AS t
       JOIN pg_stats AS s
          ON t.relname = s.tablename
             AND t.relnamespace::regnamespace::name = s.schemaname
       CROSS JOIN
          (LATERAL unnest(s.most_common_vals::text::text[]) WITH ORDINALITY AS vals(val,ord)
           JOIN
           LATERAL unnest(s.most_common_freqs::text::float8[]) WITH ORDINALITY AS freqs(freq,ord)
              USING (ord)
          )
    WHERE s.tablename = 'simcards'
      AND s.attname = 'card_state'
      AND vals.val = 'ACTIVATED';
    
  2. Если вам нужны точные значения, создайте дополнительную «таблицу счетчиков» и триггеры на simcards, которые обновляют счетчик при добавлении, удалении или изменении строк.

Для более подробное обсуждение читайте в моем блоге .

0 голосов
/ 28 февраля 2020

Тестируете ли вы установку max_parallel_workers_per_gather = 4; параметр?

Возможно, здесь вам поможет какая-то дополнительная работница

С уважением

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