在 PostgreSQL 中检查行是不是存在非常慢
Posted
技术标签:
【中文标题】在 PostgreSQL 中检查行是不是存在非常慢【英文标题】:Checking if a row exists is very slow in PostgreSQL在 PostgreSQL 中检查行是否存在非常慢 【发布时间】:2020-12-03 16:31:17 【问题描述】:我有一个product
表,它有一个索引 列manufacturer_id
。该表有 30M 行。我想检查表中是否存在特定行。我使用的查询:
select exists(select 1 from product where manufacturer_id = '0');
select 1 from product where manufacturer_id = '0' fetch first row only;
select 1 from product where manufacturer_id = '0' limit 1;
每个查询需要 4 分钟。表中有 12M 行带有manufacturer_id = '0'
。但是,如果我使用 manufacturer_id = '1234567'
(表中有 2 行)运行相同的查询,它会在 250 毫秒内返回结果。
我希望检查行的存在不会花费很长时间。或者,我是不是弄错了,考虑到桌子的容量,花那么长时间是正常的?如果不正常,如何提高性能?
执行计划:
Result (cost=0.07..0.08 rows=1 width=1) (actual time=0.015..0.016 rows=1 loops=1)
Buffers: shared hit=1
InitPlan 1 (returns $0)
-> Seq Scan on product (cost=0.00..914306.95 rows=12306868 width=0) (actual time=0.014..0.014 rows=1 loops=1)
Filter: ((manufacturer_id)::text = '0'::text)
Buffers: shared hit=1
Planning Time: 0.093 ms
Execution Time: 0.036 ms
创建索引语句:(这是除主键之外的唯一索引)
create index product_manufacturer_id
on product (manufacturer_id);
manufacturer_id: varchar
类型和indexed
列。
Postgres 版本:12
【问题讨论】:
manufacturer_id
是什么数据类型?如果那是int
或bigint
,则必须将其与数字进行比较。 '1234567'
是一个字符串,因此无法使用索引,请改用 where manufacturer_id = 1234567
。这在使用explain (analyze)
生成的执行计划中很容易看到
该列是varchar
类型并且已经有一个index
。我编辑了问题。
那么请edit您的问题并添加使用explain (analyze, buffers, format text)
生成的慢查询execution plan(not 只是一个“简单”的解释)作为formatted text 并确保保留计划的缩进。粘贴文本,然后将```
放在计划前一行和计划后一行。还请包括所有索引的完整 create index
语句。
计划显示运行该查询需要 0.036 毫秒秒 - 这甚至比您提到的 4 分钟还差
请向我们展示表和索引的完整 ddl。加上解释分析
【参考方案1】:
您想要在manufacturer_id
上建立索引:
create index idx_product_manufacturer_id on product(manufacturer_id)
您可能需要manufacturer_id
之后的其他键来支持其他查询。但是manufacturer_id
必须是第一列
此外,您需要注意类型。所以,你希望比较使用相同的类型——双引号意味着比较是字符串而不是整数。并且即使它们都是字符串,如果排序规则不同,也可能无法使用索引。
没有索引,Postgres 必须扫描表以找到匹配项。显然,'1234567'
会以 Postgres 扫描的任何顺序快速显示。但是'0'
没有。
索引解决了这个问题。而且它也有助于加入manufacturers
表。
【讨论】:
该列是varchar
类型并且已经有一个index
。我编辑了问题。以上是关于在 PostgreSQL 中检查行是不是存在非常慢的主要内容,如果未能解决你的问题,请参考以下文章