中等大 table 上的 Postgresql 简单查询非常慢
Postgresql simple query on moderately large table is extremely slow
我在 Google SQL 上有一个 PostgresSQL 数据库 :
- 4 个 vCPU
- 15 GB 内存
- 55 GB SSD
相关架构是:
postgres=> \d device;
Table "public.device"
Column | Type | Collation | Nullable | Default
-------------------------+-------------------------+-----------+----------+---------
id | uuid | | not null |
brand | character varying(255) | | |
model | character varying(255) | | |
serialnumber | character varying(255) | | |
[...]
Indexes:
"device_pkey" PRIMARY KEY, btree (id)
[...]
Referenced by:
TABLE "application" CONSTRAINT "fk_application_device_id_device" FOREIGN KEY (device_id) REFERENCES device(id) ON DELETE CASCADE
[...]
postgres=> \d application;
Table "public.application"
Column | Type | Collation | Nullable | Default
----------------------------+------------------------+-----------+----------+---------
id | uuid | | not null |
device_id | uuid | | not null |
packagename | character varying(255) | | |
versionname | character varying(255) | | |
[...]
Indexes:
"application_pkey" PRIMARY KEY, btree (id)
"application_device_id_packagename_key" UNIQUE CONSTRAINT, btree (device_id, packagename)
Foreign-key constraints:
"fk_application_device_id_device" FOREIGN KEY (device_id) REFERENCES device(id) ON DELETE CASCADE
[...]
体积:
device
table:16k 行
application
:360 万行
尝试像这样简单的事情时:
select count(id) from application;
查询用了 900 秒(原文如此)来计算这 360 万行。
执行计划如下:
postgres=> explain analyze select count(id) from application;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------
Finalize Aggregate (cost=1245180.18..1245180.19 rows=1 width=8) (actual time=311470.250..311496.933 rows=1 loops=1)
-> Gather (cost=1245179.96..1245180.17 rows=2 width=8) (actual time=311470.225..311496.919 rows=3 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Partial Aggregate (cost=1244179.96..1244179.97 rows=1 width=8) (actual time=311463.287..311463.289 rows=1 loops=3)
-> Parallel Seq Scan on application (cost=0.00..1234885.77 rows=3717677 width=16) (actual time=79.783..311296.505 rows=1202169 loops=3)
Planning Time: 0.083 ms
Execution Time: 311497.021 ms
(8 rows)
似乎一切(如键和索引)都已正确设置,那么这个简单的查询花费这么长时间的原因可能是什么?
你必须深入观察才能确定原因:
在 PostgreSQL 配置中打开 track_io_timing
这样你就可以看到 I/O 需要多长时间
使用EXPLAIN (ANALYZE, BUFFERS)
查看触摸了多少个 8kB 块
如果块数非常多,您的 table 就会膨胀(几乎什么都没有),并且顺序扫描会花费很长时间,因为它必须读取所有空的 space。 VACUUM (FULL)
可以提供帮助。
如果块数与您预期的一样,则问题是您的存储速度太慢。
我在 Google SQL 上有一个 PostgresSQL 数据库 :
- 4 个 vCPU
- 15 GB 内存
- 55 GB SSD
相关架构是:
postgres=> \d device;
Table "public.device"
Column | Type | Collation | Nullable | Default
-------------------------+-------------------------+-----------+----------+---------
id | uuid | | not null |
brand | character varying(255) | | |
model | character varying(255) | | |
serialnumber | character varying(255) | | |
[...]
Indexes:
"device_pkey" PRIMARY KEY, btree (id)
[...]
Referenced by:
TABLE "application" CONSTRAINT "fk_application_device_id_device" FOREIGN KEY (device_id) REFERENCES device(id) ON DELETE CASCADE
[...]
postgres=> \d application;
Table "public.application"
Column | Type | Collation | Nullable | Default
----------------------------+------------------------+-----------+----------+---------
id | uuid | | not null |
device_id | uuid | | not null |
packagename | character varying(255) | | |
versionname | character varying(255) | | |
[...]
Indexes:
"application_pkey" PRIMARY KEY, btree (id)
"application_device_id_packagename_key" UNIQUE CONSTRAINT, btree (device_id, packagename)
Foreign-key constraints:
"fk_application_device_id_device" FOREIGN KEY (device_id) REFERENCES device(id) ON DELETE CASCADE
[...]
体积:
device
table:16k 行application
:360 万行
尝试像这样简单的事情时:
select count(id) from application;
查询用了 900 秒(原文如此)来计算这 360 万行。
执行计划如下:
postgres=> explain analyze select count(id) from application;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------
Finalize Aggregate (cost=1245180.18..1245180.19 rows=1 width=8) (actual time=311470.250..311496.933 rows=1 loops=1)
-> Gather (cost=1245179.96..1245180.17 rows=2 width=8) (actual time=311470.225..311496.919 rows=3 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Partial Aggregate (cost=1244179.96..1244179.97 rows=1 width=8) (actual time=311463.287..311463.289 rows=1 loops=3)
-> Parallel Seq Scan on application (cost=0.00..1234885.77 rows=3717677 width=16) (actual time=79.783..311296.505 rows=1202169 loops=3)
Planning Time: 0.083 ms
Execution Time: 311497.021 ms
(8 rows)
似乎一切(如键和索引)都已正确设置,那么这个简单的查询花费这么长时间的原因可能是什么?
你必须深入观察才能确定原因:
在 PostgreSQL 配置中打开
track_io_timing
这样你就可以看到 I/O 需要多长时间使用
EXPLAIN (ANALYZE, BUFFERS)
查看触摸了多少个 8kB 块
如果块数非常多,您的 table 就会膨胀(几乎什么都没有),并且顺序扫描会花费很长时间,因为它必须读取所有空的 space。 VACUUM (FULL)
可以提供帮助。
如果块数与您预期的一样,则问题是您的存储速度太慢。