簡體   English   中英

慢計數PostgreSQL

[英]Slow count postgresql

我有一個包含36M條目的表,並且我想根據索引/外鍵對其中一些條目進行計數。

這是我的要求:

SELECT count(*) 
FROM batch_item 
WHERE batch_id = '38212ee5-84b4-4c08-99a7-7f30ac52f4bf'

batch_id是一個索引字段。 為什么此請求需要4秒鍾?

編輯:我在此表中有36個不同的batch_id。 我創建了這樣的表和索引:

create table batch_item
(
  id               uuid         not null
    constraint batch_item_pkey
    primary key,
  batch_id         uuid
    constraint fk_8f7fcfe1f39ebe7a
    references batch
    on delete cascade,
  source_code      varchar(255) not null,
  target_code      varchar(255) default NULL :: character varying,
  status           varchar(255),
  description      varchar(255) not null,
  infos            json,
  target_code_tops json,
  added_on         timestamp(0) not null,
  updated_on       timestamp(0) not null,
  code_fake        varchar(255) default NULL :: character varying,
  stat_target_code varchar(255) default NULL :: character varying,
  stats_infos      json,
  processed        boolean      not null
);

create index idx_8f7fcfe1f39ebe7a
  on batch_item (batch_id);

create index idx_8f7fcfe17b00651c
  on batch_item (status);

create index batch_item_si_kcf_index
  on batch_item ((stats_infos ->> 'keycatFinder' :: text));

create index batch_item_tct_best_keycat_index
  on batch_item ((((target_code_tops ->> 'best' :: text) :: json) ->> 'keycat' :: text));

create index batch_item_tct_low_keycat_index
  on batch_item ((((target_code_tops ->> 'low' :: text) :: json) ->> 'keycat' :: text));

create index idx_8f7fcfe1ba0d2629
  on batch_item (target_code);
create index idx_8f7fcfe1fb269bae
  on batch_item (code_fake);
create index idx_8f7fcfe1769fb59b
  on batch_item (source_code);
create index idx_8f7fcfe16de44026
  on batch_item (description);
create index idx_8f7fcfe127fb1b8b
  on batch_item (processed);
create index idx_8f7fcfe127fb1b8bf39ebe7a
  on batch_item (processed, batch_id);

explain analyze結果explain analyze

Finalize Aggregate  (cost=2974200.67..2974200.68 rows=1 width=8) (actual time=51735.494..51735.494 rows=1 loops=1)
->  Gather  (cost=2974200.46..2974200.67 rows=2 width=8) (actual time=51735.378..51738.653 rows=3 loops=1)
    Workers Planned: 2
    Workers Launched: 2
    ->  Partial Aggregate  (cost=2973200.46..2973200.47 rows=1 width=8) (actual time=51690.519..51690.519 rows=1 loops=3)
          ->  Parallel Seq Scan on batch_item  (cost=0.00..2964145.93 rows=3621812 width=0) (actual time=3161.252..51381.176 rows=1929799 loops=3)
                Filter: (batch_id = '38212ee5-84b4-4c08-99a7-7f30ac52f4bf'::uuid)
                Rows Removed by Filter: 10187060
Planning time: 0.139 ms
Execution time: 51738.693 ms

是的,Postgres中的COUNT()讀取所有行並變得非常慢。

解決方案1.將COUNT()結果保存在獨立表中。

步驟1.創建表:

CREATE TABLE batch_item_counts (
  batch_id uuid,
  "count" bigint default 0
);

該表只有36行-每1個唯一的batch_id 1行。

步驟2.通過此類查詢初始化值

INSERT INTO batch_item_counts
SELECT batch_id, COUNT(1)
FROM batch_item
GROUP BY batch_id;

步驟3.通過觸發器在主表FOR INSERT OR UPDATE OR DELETE FOR EACH ROW保留實際值 ,這會重新計算項目。 注意:當將新的batch_id值插入主表時,觸發器必須插入新行,而當從主表中完全刪除現有的batch_id值時,觸發器必須刪除現有行。


解決方案2。更簡單,但近似。

將系統統計信息表或解析器用於EXPLAIN query結果以獲取近似的 COUNT()。 詳細信息在這里。


注意:由於經常重復使用主表值,所以batch_id索引利潤很小-在3,600萬行中只有36個不同的值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM