我有一个 PostgreSQL 表,它在 4 列上定义了一个唯一约束:
create table public.values (
id bigint primary key generated always as identity,
a smallint not null references .... (id),
b smallint not null,
c smallint not null,
d int not null references .... (id),
-- ... some other cols
constraint unique_cols unique (a, b, c, d)
);
create index values_d on public.values using btree (dasc);
这张表有很多行(它是 +/- 400GB 并且每天增长 8GB)——我认为此时它大约有 25 亿行。我想删除通过 column 标识的行a
,但除非我在 where 子句中指定b
或指定,否则c
查询计划表明将执行顺序扫描public.values
。
即这个查询:
-- ... After running `analyze` on the tables that are used
explain delete from public.values where a = 2
显示查询计划(具有 60 个唯一a
值):
Delete on "values" (cost=0.00..62375313.80 rows=0 width=0)
-> Seq Scan on "values" (cost=0.00..62375313.80 rows=48160325 width=6)
Filter: (a = 2)
JIT:
Functions: 3
Options: Inlining true, Optimization true, Expressions true, Deforming true
这对我来说毫无意义——我不明白为什么不使用唯一约束索引(我希望这个查询会删除 5000 万行)。
如果我将查询更新为指定b
,那么我可以获得查询计划以指示将完成索引扫描:
explain delete from public.values where a = 2 and b = 1
显示此查询计划:
Delete on "values" (cost=0.58..4845719.33 rows=0 width=0)
-> Index Scan using values_unique_cols on "values" (cost=0.58..4845719.33 rows=1940861 width=6)
Index Cond: ((a = 2) AND (b = 1))
JIT:
Functions: 3
Options: Inlining true, Optimization true, Expressions true, Deforming true
然后,如果我将删除查询b
子句“where”条件更改为greater than
条件:
explain delete from public.values where a = 2 and b >= 1
...回到顺序扫描。
但是再次更改子句:
explain delete from public.values where a = 2 and b >= 7
并且计划更好(b lower than 6
导致 seq 扫描 - b 是 1 到 20 之间的值):
Delete on "values" (cost=0.58..65344628.48 rows=0 width=0)
-> Index Scan using values_unique_cols on "values" (cost=0.58..65344628.48 rows=36595426 width=6)
Index Cond: ((a = 2) AND (b >= 7))
JIT:
Functions: 3
Options: Inlining true, Optimization true, Expressions true, Deforming true
如何强制 PostgreSQL 为特定操作使用索引,或者快速删除大量行?
我可以从应用程序多次运行查询,每次都使用一个新b
值,但我更愿意进行一次数据库调用。
== 编辑
随后发布此问题,我在 上创建了一个索引a
,并重新分析了该表。但是规划器仍然指示一个seq。扫描。
不,您不能强制PostgreSQL 为命令使用索引。您必须使索引足够开胃,以便计划者选择它。
根据您对表活动的描述,我怀疑您的列统计信息不准确,这会导致计划选择失败。您还可以通过更改 I/O 成本值来影响规划器,以在索引扫描和顺序扫描之间移动阈值,但有龙。
至于级联删除,将取决于规划器如何构建子查询。我认为它会转化为类似的东西
DELETE FROM values WHERE a=2 AND d=2
,它将打破 的选择性d
是否优于a
,因此如果values_d
索引比唯一索引更有用,如果有的话。参考: