我有一个表,有36M个条目,我想根据索引/外键计算其中的一些条目。
这是我的请求:
SELECT count(*)
FROM batch_item
WHERE batch_id = '38212ee5-84b4-4c08-99a7-7f30ac52f4bf'
batch_id
是索引字段。为什么这个请求需要4秒钟?编辑:
我这张桌子上有36个不同的批号。
我创建了如下表和索引:
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
的结果: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
最佳答案
是的,COUNT()
在Postgres中读取所有行并变得非常慢。
解决方案1。将COUNT()
结果保存在独立表中。
第一步。创建表:
CREATE TABLE batch_item_counts (
batch_id uuid,
"count" bigint default 0
);
这个表只有36行-每1行只有1行。
第二步。通过这样的查询初始化值:
INSERT INTO batch_item_counts
SELECT batch_id, COUNT(1)
FROM batch_item
GROUP BY batch_id;
第三步。通过主表上的触发器将值保持为实际值
batch_id
这将重新计算项目。注意:当新的FOR INSERT OR UPDATE OR DELETE FOR EACH ROW
值插入主表时,触发器必须插入新行,当现有的“cc>值从主表中完全删除时,删除现有行。解决方案2。简单,但近似。
使用系统统计表或解析器对
batch_id
的结果得到近似计数()。Details here.注意:
batch_id
上的索引将有非常小的利润,因为主表值经常重复-您在36M行上只有36个不同的值。关于sql - 慢计数PostgreSQL,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/51999307/