故障排除性能

请使用以下指南来排查性能 IBM Cloud® Databases for PostgreSQL 问题。

有关总体概述,请参见 PostgreSQL 性能。

数据库运行缓慢

该问题的典型症状如下:

  • 磁盘输入/输出(I/O)或内存使用率过高
  • 慢速查询

最常见的原因是正在检查慢查询。 请完成以下步骤以确定是否如此:

  1. 列出长期运行的查询:

    select age(now(),query_start), pid, client_addr, state, substring(query,0,80) from pg_stat_activity where state != 'idle' order by 1 desc;
    
  2. 验证查询阻塞:

    select pg_blocking_pids(pid), pid AS blocked_pid, state, query, age(now(),query_start) AS duration from pg_stat_activity where array_length(pg_blocking_pids(pid),1) > 0 order by 1,2;
    
  3. 检查查询执行计划:

    Explain <query>;
    
  4. 检查数据库统计信息是否缺失。 使用以下查询进行验证:操作 > 运行分析 或者,运行以下命令:

    Analyze <tablename>  select relname, n_live_tup, n_dead_tup, last_vacuum,last_autovacuum,last_analyze,last_autoanalyze, analyze_count,autoanalyze_count from pg_stat_all_tables where schemaname='public';
    
  5. 检查表中是否缺少索引。 PostgreSQL 提供索引方法,例如B树、哈希、SP-GiST,GiST, GIN和BRIN。 使用其中一种方法创建索引。

  6. 检查表是否膨胀。 运行以下查询进行验证。 操作 > 运行真空

    或者,使用以下语句:

    SELECT
    relname AS table_name,
    pg_size_pretty(pg_relation_size(c.oid)) AS actual_size,
    pg_size_pretty(
    CASE
    WHEN c.relpages = 0 THEN 0
    ELSE (pg_relation_size(c.oid) - (c.relpages *
    (current_setting('block_size')::numeric - 24))) * 100 / pg_relation_size(c.oid)
    END
    ) AS bloat_percentage, pg_size_pretty(
    CASE
    WHEN c.relpages = 0 THEN 0
    ELSE (pg_relation_size(c.oid) - (c.relpages *
    (current_setting('block_size')::numeric - 24)))
    END
    )AS bloat_size
    FROM pg_class c
    LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
    WHERE relkind = 'r' AND n.nspname = 'public' -- Adjust schema if needed
    ORDER BY bloat_size DESC NULLS LAST;
    
  7. 请考虑数据库或对象是否已使用 pg_dump 或 创建 pg_restore。 使用操作 > 更新统计数据进行刷新。

  8. 确保分配 work_mem 足够的内存,如果查询正在执行排序操作。

  9. 使用 pg_stat 语句来获取以下信息:

    • 查询平均执行时间和调用次数

    • CPU百分比使用率由查询产生

    • 查询占用的内存百分比

pg_stat_activity, pg_stat_bgwriter,和 pg_buffercache 是 PostgreSQL 用于监控和理解数据库性能的重要工具。

部署监控与数据库负载监控

Databases for PostgreSQL 部署提供与 IBM Cloud Monitoring 服务的集成,用于监控您部署中的资源使用情况。 使用此服务监控您的部署(磁盘和内存)以及数据库负载。

使用 Cloud Databases 仪表板设置CPU、内存和磁盘IOPS阈值的警报。 许多可用的指标(如磁盘使用率和IOPS)有助于您为部署配置 自动缩放功能。 自动缩放功能默认未启用,因此您必须手动进行配置。

通过观察使用趋势并配置自动扩展功能以响应这些趋势,可在数据库因资源耗尽而变得不稳定之前缓解性能问题。 例如,磁盘I/O、CPU或内存故障的变化导致性能问题。

磁盘 IOPS

每秒输入/输出操作数(IOPS)受存储卷的类型和大小限制。 部署 Databases for PostgreSQL 的存储卷在 Block Storage 持久卷 上进行配置,采用每GB 10 IOPS的性能层级。

若您的操作负载达到或超过IOPS限制,数据库请求和操作将被延迟,直至存储子系统能够跟上处理进度。 长时间的高负载可能导致部署无法处理查询,从而实质上无法使用。 您可以通过增加磁盘容量来提升部署环境的可用IOPS数量。 例如,对于每GB层级10 IOPS的情况,您可以通过增加卷大小来提升IOPS。

即使磁盘利用率在40-50%的状态下持续较长时间,也会对数据库性能产生显著的负面影响。 为生产环境分配至少100 GB磁盘空间(1,000 IOPS)。 IOPS = 10 × 分配的GB(例如,100 GB = 1,000 IOPS)

内存使用率

内存是访问和处理数据最快捷、最高效的方式。 因此,数据库使用内存处理数据时,其运行速度几乎总是快于从磁盘读取数据。 还有其他指标需要关注和考虑,例如缓存命中率、读取的块数以及命中的块数。 仅看到100%的内存使用率本身并不值得担忧。 若内存耗尽并启用交换页,性能可能显著下降。

您可以在配置文件 Databases for PostgreSQL 中调整 shared_buffers 参数,来设定分配给数据库共享缓冲池的内存大小。 建议的最大值为部署总内存的25%。 为共享缓冲池分配过多内存会导致系统其他用途的内存不足,可能影响性能,甚至可能导致数据库无法运行。

数据库负载监控

检查数据库负载有两种方式:

选择 1. 使用 IBM Cloud Logs ( ICL ) 检查长时间运行的查询:

有关更多信息,请 参阅《如何追踪查询历史记录?》

您可以在. IBM Cloud Logs 中使用以下示例 DataPrime 查询。

  1. 加载日志 IBM Cloud 后,切换到标签 </>DataPrime 页。 请勿更改 </>Lucene 搜索栏中的任何内容。
  2. 在选项卡 </>DataPrime 中,运行以下搜索以查找运行时间超过1000毫秒的SQL语句。 您也可以将其粘贴到标签 </>DataPrime 页的搜索框中。
{

source logs|filter message.attr.durationMillis>=1000

}

选项2。 启用 log_min_duration_statement

使用 log_timeout 参数 log_min_duration_statement 可指定超过指定毫秒数执行的语句将被记录。 有关更多信息,请参阅 log_min_duration_statement。

您还可以安装 pg_stat_statements 扩展:

CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

此扩展程序允许您查询统计数据,以查找运行时间特别长的查询示例。 随后,您可以隔离问题并考虑采用不同的查询模式、新建或修改索引、调整表结构设计,或采取其他策略来提升性能。

查询1:识别耗时查询

您可以通过运行以下语句来识别耗时的查询:

SELECT username, database, queryid, query_preview, calls, total_exec_time, pct_exec_time, ROUND(SUM(pct_exec_time) OVER (ORDER BY total_exec_time DESC)) AS cum_pct_exec_time, avg_exec_time FROM ( SELECT pu.usename AS username, pd.datname AS database, pss.queryid, LEFT(pss.query, 50) AS query_preview, pss.calls, ROUND(pss.total_exec_time::numeric, 3) AS total_exec_time, ROUND((100.0 * pss.total_exec_time / SUM(pss.total_exec_time) OVER ())::numeric, 2) AS pct_exec_time, ROUND(pss.mean_exec_time::numeric, 3) AS avg_exec_time FROM pg_stat_statements pss JOIN pg_user pu ON pss.userid = pu.usesysid JOIN pg_database pd ON pss.dbid = pd.oid ) AS subquery ORDER BY total_exec_time DESC LIMIT 25;

此语句产生以下结果:

耗时查询语句的结果
用户名 数据库 查询ID 查询预览 调用数 总执行时间 百分比执行时间 cum_pct_执行时间 平均执行时间
IBM postgres <权限不足> 50685 38286.580 19.52 20 0.755
ibm postgres <权限不足> 280111 28477.951 14.52 34 0.102
ibm postgres <权限不足> 18 14568.978 7.43 41 809.388
ibm postgres <权限不足> 18 12103.904 6.17 48 672.439
ibm IBM Cloud DB <权限不足> 37552 7799.984 3.98 52 0.208
(5行)

该查询跟踪SQL语句的执行统计信息,并提供以下内容:

  • 显示耗时最长的25个查询
  • 显示执行查询的用户、所操作的数据库以及查询的预览内容
  • 显示每个查询的运行频率及其平均耗时
  • 计算每个查询占用数据库总时间的百分比
  • 提供数据库使用时间的累计值

查询2:识别频繁执行的查询

您可以通过执行以下语句来识别频繁运行的查询:

SELECT
   username,
   database,
   queryid,
   query_preview,
   calls,
   pct_calls,
   ROUND(SUM(pct_calls) OVER (ORDER BY calls DESC)) AS cum_pct_calls,
   total_exec_time,
   avg_exec_time
FROM (
   SELECT
      pu.usename AS username,
      pd.datname AS database,
      pss.queryid,
      LEFT(pss.query, 50) AS query_preview,
      pss.calls,
      ROUND(100.0 * pss.calls / SUM(pss.calls) OVER (), 2) AS pct_calls,
      ROUND(pss.total_exec_time::numeric, 3) AS total_exec_time,
      ROUND(pss.mean_exec_time::numeric, 3) AS avg_exec_time
   FROM
      pg_stat_statements pss
      JOIN pg_user pu ON pss.userid = pu.usesysid
      JOIN pg_database pd ON pss.dbid = pd.oid
) AS subquery
ORDER BY
   calls DESC
LIMIT 25;

此语句产生以下结果:

频繁执行的查询语句结果
用户名 数据库 查询ID 查询预览 调用次数 百分比呼叫 累计通话次数 总执行时间 平均执行时间
IBM postgres <权限不足> 80285 23.84 24 16095.420 0.200
IBM postgres <权限不足> 36832 10.94 35 548.787 0.015
IBM postgres <权限不足> 20626 6.12 41 741.755 0.036
IBM postgres <权限不足> 14702 4.36 45 23982.252 1.631
IBM postgres <权限不足> 12436 3.69 49 1750.426 0.141

该查询提供以下信息:

  • 显示运行次数最多的25个查询
  • 显示执行查询的用户、所操作的数据库以及查询的预览内容
  • 显示每个查询的执行次数、总耗时及平均耗时
  • 计算每个查询占所有查询调用总数的百分比
  • 提供查询调用的累计总数

获取所有查询的当前性能

  1. 要获取所有查询的当前性能,请运行以下语句:

    select now() as t1,sum(total_exec_time) as et1, sum(calls) as c1 from pg_stat_statements
    

    这产生以下结果:

    当前所有查询语句的执行结果
    t1 et1 c1
    2025-09-30 08:15:43.898157 +00 104109.55454499979 336889
    (1 row)
  2. 然后等待10秒,并执行以下语句:

    select now() as t2,sum(total_exec_time) as et2, sum(calls) as c2 from pg_stat_statements
    

    这产生以下结果:

    select now() 语句的结果
    t2 et2 c2
    2025-09-30 08:16:18.943609 +00 104113.70054399982 336896
    (1 row)
  3. 计算每秒查询次数:

    Queries per second = (c2-c1)/(t2-t1) and average query performance = (et2-et1)/(c2-c1)
    

十大耗时查询

获取耗时最多的前10个查询:

SELECT query, calls, total_exec_time/calls as avg_time
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 10;

这产生以下结果:

| 查询 | 调用次数 | 平均时间 |   | | -------------- | -------------- | -------------- | | <权限不足> | 14706 |   1.6311896077791408 | | <权限不足> | 80305 |   0.2004813740987463 | | <权限不足> |     6 |   800.7297508333332 | | <权限不足> |     6 |   721.1415835000001 | | <权限不足> | 10316 |   0.3907427791779766 | | <权限不足> | 10316 | 0.35429842613416024 | | <权限不足> | 10316 |   0.3184477990500202 | | <权限不足> | 10316 |   0.2285179489143081 | | <权限不足> | 12439 |   0.1407493980223488 | | <权限不足> | 10316 |   0.1605010507948812 | | (10行) | | |

您可采取的进一步措施以提升性能

您还可以考虑采取以下措施来排查性能问题:

  • 优化慢查询

    • 对运行缓慢的查询执行EXPLAIN (ANALYZE, BUFFERS)。 这显示了数据库是如何运行查询的,以及在哪些地方运行缓慢。 例如:
    EXPLAIN (ANALYZE, BUFFERS)
    SELECT * FROM student WHERE student_id = 12345;
    
    • 寻找:

      • 占用大量内存或磁盘空间的查询

      • 根据需要添加 IBM Cloud 资源

      • 扩展磁盘/内存以获得更高的IOPS和内存容量

  • 缺失或低效的索引是导致查询缓慢的常见原因。 使用EXPLAIN来识别顺序扫描,并考虑添加索引。

  • 运行 VACUUM 命令以协助数据库健康分析。

  • 考虑使用连接池来处理更多连接。Databases for PostgreSQL 将数据库 Databases for PostgreSQL 的最大连接数设置为 115。 其中15个连接预留给超级用户用于维护数据库状态和完整性,其余100个连接可供您和您的应用程序使用。 达到连接限制后,任何尝试建立新连接的行为都会导致错误。 为避免部署因连接过载而崩溃,请使用连接池技术,或扩展部署规模并提高其连接限制。 有关更多信息,请参阅 管理 PostgreSQL 连接池。

  • 检查是否有任何程序正在执行备份和批量上传数据,例如: 自动备份每日完成,并采用30天的简单保留周期进行存储。 如果备份卡住,您可以在数据库实例的云管理界面中查看“可用备份”部分,从而识别出卡住的备份。

  • 请查看您的 IBM Cloud 通知以了解任何维护信息。 例如,数据库修补。

  • 若您认为这是平台问题(例如维护),请联系 IBM 支持团队并提供数据库CRN。