【问题标题】:Postgresql simple query on moderately large table is extremely slowPostgresql对中等大表的简单查询非常慢
【发布时间】:2021-06-25 08:29:00
【问题描述】:

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

  • 4 个 vCPUS
  • 15 GB 内存
  • 55 GB 固态硬盘

相关架构是:

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 表: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)

似乎所有内容(如键和索引)都已正确设置,那么这个简单查询需要这么长时间的原因可能是什么?

【问题讨论】:

  • 也许是解释Slow Counting, Count estimate
  • @Philippe 是的,我看到了这个页面,但是即使它读取每一行也需要这么长时间,这不是很奇怪吗?无论如何,使用估计是不可接受的,因为我不知道如何通过常规数据库工具(ORM 等)使用它,而且我们的需求不会仅通过估计来满足......
  • 是的,我能理解您的沮丧,但据我所知,没有其他方法可以获取此信息。
  • 我不熟悉 Google SQL - 他们提供 IOPS 保证吗?在 Azure 数据库中,当 所有 操作变慢而没有任何明显原因时,我们遇到了 IOPS 限制的情况。例如。您重新索引表或重建 matview,然后简单的键查找开始需要几秒钟才能完成。
  • 另一点:我宁愿期待Index Only Scan using application_pkey而不是Seq Scan on application

标签: postgresql google-cloud-sql


【解决方案1】:

你必须深入研究才能确定原因:

  • 在 PostgreSQL 配置中打开track_io_timing,这样你就可以看到 I/O 需要多长时间

  • 使用EXPLAIN (ANALYZE, BUFFERS)查看有多少8kB的块被触摸

如果块的数量非常多,那么您的表就会变得臃肿(几乎什么都没有),并且顺序扫描需要很长时间,因为它必须读取所有的空白空间。 VACUUM (FULL) 可以提供帮助。

如果块数如你所料,问题是你的存储太慢了。

【讨论】:

  • 你是对的,该表因大量删除/插入而变得臃肿。 VACUUM (FULL) 修复了它,并且必须更改一些持久性方法。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-06
  • 2020-11-21
  • 1970-01-01
  • 2020-03-26
相关资源
最近更新 更多