高 CPU 利用率会对实例的性能产生不利影响。在实例上执行的任何活动都会使用 CPU。因此,如果出现 CPU 利用率过高通知,您应先找出问题的根本原因,无论是编写不当的查询、运行时间过长的事务,还是任何其他数据库活动。
本文档介绍识别实例中的 CPU 瓶颈并缓解实例中的 CPU 利用率问题的方法。
确定 CPU 瓶颈
使用 Query Insights 来识别 CPU 耗用量较高的查询
Query Insights 可帮助您检测、诊断和避免 Cloud SQL 数据库的查询性能问题。
使用 pg_proctab
扩展程序
将 pg_proctab 扩展程序与 pg_top
实用程序结合使用,以获取提供每个进程的 CPU 利用率信息的操作系统输出。
使用查询
按状态确定活跃连接
与数据库的每个活跃连接都会占用一定数量的 CPU,因此,如果实例具有大量连接,则累计利用率可能较高。使用以下查询按状态获取有关连接数的信息。
SELECT
state,
usename,
count(1)
FROM
pg_stat_activity
WHERE
pid <> pg_backend_pid()
group by
state,
usename
order by
1;
输出类似于以下内容:
state | usename | count
---------------------+---------------+-------
active | ltest | 318
active | sbtest | 95
active | | 2
idle | cloudsqladmin | 2
idle in transaction | ltest | 32
idle in transaction | sbtest | 5
| cloudsqladmin | 3
| | 4
(8 rows)
如果活跃连接数较高,请检查是否存在长时间运行的查询或阻止查询执行的等待事件。
如果空闲连接数量较高,请在获得必要的批准后执行以下查询以终止连接。
SELECT
pg_terminate_backend(pid)
FROM
pg_stat_activity
WHERE
usename = 'sbtest'
and pid <> pg_backend_pid()
and state in ('idle');
您还可以使用以下查询通过 pg_terminate_backend
逐个终止连接:
SELECT pg_terminate_backend (<pid>);
在这里,您可以从 pg_stat_activity
获取 PID。
确定长时间运行的连接
以下示例演示了如何返回长时间运行的查询。在此示例中,您可以识别活跃时间超过 5 分钟的查询。
SELECT
pid,
query_start,
xact_start,
now() - pg_stat_activity.query_start AS duration,
query,
state
FROM
pg_stat_activity
WHERE
(
now() - pg_stat_activity.query_start
) > interval '5 minutes' order by 4 desc;
查看说明计划以确定编写不佳的查询
使用说明计划调查编写不佳的查询,并根据需要重写查询。(可选)考虑在必要的批准下使用以下命令取消长时间运行的查询。
SELECT pg_cancel_backend(<pid>);
监控 VACUUM 活动
用于清除已弃用元组的 AUTOVACUUM 活动是一项占用大量 CPU 的操作。如果您的实例使用 PostgreSQL 11 或更高版本,请使用以下查询检查是否有任何正在进行的 AUTOVACUUM 或 VACUUM 活动。
SELECT
relid :: regclass,
pid,
phase,
heap_blks_total,
heap_blks_scanned,
heap_blks_vacuumed,
index_vacuum_count,
max_dead_tuples,
num_dead_tuples
FROM
pg_stat_progress_vacuum;
使用以下查询检查实例中是否有正在进行的 VACUUM 活动:
SELECT
pid,
datname,
usename,
query
FROM
pg_stat_activity
WHERE
query like '%vacuum%';
此外,您还可以在 PostgreSQL 中优化 VACUUM 操作并排查相关问题。
添加 pg_stat_statements 扩展程序
设置 pg_stat_statements
扩展程序,以获取有关实例活动的增强型字典信息。
频繁的检查点
频繁的检查点会降低性能。如果 PostgreSQL 提醒日志报告 checkpoint occurring too frequently
警告,请考虑调整 checkpoint_timeout
标志。
收集统计信息
确保查询规划器具有有关表的最新统计信息,以便选择最佳查询计划。ANALYZE 操作会收集有关数据库中表的内容的统计信息,并将结果存储在 pg_statistic 系统目录中。随后,查询规划器会使用这些统计信息来帮助确定最有效的查询执行计划。AUTOVACUUM 流程会定期自动分析表,因此运行以下命令可检查所有表是否均已分析,以及是否具有可用于规划器的最新元数据。
SELECT
relname,
last_autovacuum,
last_autoanalyze
FROM
pg_stat_user_tables;
系统设置不足
还有其他因素和标志设置或系统因素会影响查询性能。运行以下查询以检查等待事件和等待事件类型,以深入了解其他系统设置的性能。
SELECT
datname,
usename,
(
case when usename is not null then state else query end
) AS what,
wait_event_type,
wait_event,
backend_type,
count(*)
FROM
pg_stat_activity
GROUP BY
1,
2,
3,
4,
5,
6
ORDER BY
1,
2,
3,
4 nulls first,
5,
6;
输出类似于以下内容:
.. | .. | what | wait_event_type | wait_event | .. | count
-..--+-..-+----------------+-----------------+----------------------+-..----+------
..
.. | .. | active | IO | CommitWaitFlush | .. | 750
.. | .. | idle | IO | CommitWaitFlush | .. | 360
.. | .. | active | LWLock | BufferMapping | .. | 191
监控顺序扫描
对超过几十行的表进行频繁的顺序扫描通常表明缺少索引。如果扫描涉及数千行甚至数十万行,则可能会导致 CPU 利用率过高。
对包含数十万行的表进行频繁的顺序扫描可能会导致 CPU 使用率过高。通过创建必要的索引来避免对此类表进行顺序扫描。
运行以下查询以检查对任何表启动顺序扫描的次数。
SELECT
relname,
idx_scan,
seq_scan,
n_live_tup
FROM
pg_stat_user_tables
WHERE
seq_scan > 0
ORDER BY
n_live_tup desc;
最后,如果 CPU 仍然较高,并且您认为这些查询是合法流量,请考虑增加实例中的 CPU 资源,以避免数据库崩溃或停机。