中等大 table 上的 Postgresql 简单查询非常慢

Postgresql simple query on moderately large table is extremely slow

我在 Google SQL 上有一个 PostgresSQL 数据库 :

相关架构是:

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
[...]

体积:

尝试像这样简单的事情时:

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) 可以提供帮助。

如果块数与您预期的一样,则问题是您的存储速度太慢。