故障排除性能
请使用以下指南来排查性能 IBM Cloud® Databases for PostgreSQL 问题。
有关总体概述,请参见 PostgreSQL 性能。
数据库运行缓慢
该问题的典型症状如下:
- 磁盘输入/输出(I/O)或内存使用率过高
- 慢速查询
最常见的原因是正在检查慢查询。 请完成以下步骤以确定是否如此:
-
列出长期运行的查询:
select age(now(),query_start), pid, client_addr, state, substring(query,0,80) from pg_stat_activity where state != 'idle' order by 1 desc; -
验证查询阻塞:
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; -
检查查询执行计划:
Explain <query>; -
检查数据库统计信息是否缺失。 使用以下查询进行验证:操作 > 运行分析 或者,运行以下命令:
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'; -
检查表中是否缺少索引。 PostgreSQL 提供索引方法,例如B树、哈希、SP-GiST,GiST, GIN和BRIN。 使用其中一种方法创建索引。
-
检查表是否膨胀。 运行以下查询进行验证。 操作 > 运行真空
或者,使用以下语句:
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; -
请考虑数据库或对象是否已使用
pg_dump或 创建pg_restore。 使用操作 > 更新统计数据进行刷新。 -
确保分配
work_mem足够的内存,如果查询正在执行排序操作。 -
使用
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 查询。
- 加载日志 IBM Cloud 后,切换到标签 </>DataPrime 页。 请勿更改 </>Lucene 搜索栏中的任何内容。
- 在选项卡 </>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个查询
- 显示执行查询的用户、所操作的数据库以及查询的预览内容
- 显示每个查询的执行次数、总耗时及平均耗时
- 计算每个查询占所有查询调用总数的百分比
- 提供查询调用的累计总数
获取所有查询的当前性能
-
要获取所有查询的当前性能,请运行以下语句:
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) -
然后等待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) -
计算每秒查询次数:
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。