

# RDS for PostgreSQL 优化的基本概念
<a name="PostgreSQL.Tuning.concepts"></a>

在优化 RDS for PostgreSQL 数据库之前，请务必了解什么是等待事件以及它们发生的原因。还可以查看 RDS for PostgreSQL 的基本内存和磁盘架构。有关有用的架构图，请参阅 [PostgreSQL](https://en.wikibooks.org/wiki/PostgreSQL/Architecture) wikibook。

**Topics**
+ [RDS for PostgreSQL 等待事件](PostgreSQL.Tuning.concepts.waits.md)
+ [RDS for PostgreSQL 内存](PostgreSQL.Tuning.concepts.memory.md)
+ [RDS for PostgreSQL 进程](PostgreSQL.Tuning.concepts.processes.md)

# RDS for PostgreSQL 等待事件
<a name="PostgreSQL.Tuning.concepts.waits"></a>

*等待事件*表示会话正在等待资源。例如，当 RDS for PostgreSQL 等待从客户端接收数据时，会发生等待事件 `Client:ClientRead`。会话通常会等待如下资源。
+ 例如，当会话试图修改缓冲区时，对缓冲区的单线程访问
+ 当前被另一个会话锁定的行
+ 已读取一个数据文件
+ 已写入一个日志文件

例如，为了满足查询，会话可能会执行完整的表扫描。如果数据尚未在内存中，会话将等待磁盘输入/输出完成。当缓冲区读取到内存时，会话可能需要等待，因为其他会话正在访问相同的缓冲区。数据库使用预定义的等待事件记录等待。这些事件按类别进行分组。

等待事件本身并不表示存在性能问题。例如，如果请求的数据不在内存中，则必须从磁盘读取数据。如果一个会话锁定行以进行更新，则另一个会话将等待解锁该行，以便它可以更新该行。提交需要等待对日志文件的写入完成。等待是数据库正常运行不可或缺的组成部分。

另一方面，大量的等待事件通常表示存在性能问题。在这种情况下，您可以使用等待事件数据来确定会话将时间花费在哪里。例如，如果通常在几分钟内运行的报告现在运行需要几个小时，则可以确定对总等待时间贡献最大的等待事件。如果您能确定顶级等待事件的原因，您有时就可以进行更改来提高性能。例如，如果您的会话正在等待已被另一个会话锁定的行，则可以结束锁定会话。

# RDS for PostgreSQL 内存
<a name="PostgreSQL.Tuning.concepts.memory"></a>

RDS for PostgreSQL 内存分为共享内存和本地内存。

**Topics**
+ [RDS for PostgreSQL 中的共享内存](#PostgreSQL.Tuning.concepts.shared)
+ [RDS for PostgreSQL 中的本地内存](#PostgreSQL.Tuning.concepts.local)

## RDS for PostgreSQL 中的共享内存
<a name="PostgreSQL.Tuning.concepts.shared"></a>

RDS for PostgreSQL 会在实例启动时分配共享内存。共享内存分为多个子区域。以下各节提供了最重要子区域的说明。

**Topics**
+ [共享缓冲区](#PostgreSQL.Tuning.concepts.buffer-pool)
+ [预写日志 (WAL) 缓冲区](#PostgreSQL.Tuning.concepts.WAL)

### 共享缓冲区
<a name="PostgreSQL.Tuning.concepts.buffer-pool"></a>

*共享缓冲池*是一个 RDS for PostgreSQL 内存区域，它包含应用程序连接现在正在使用或过去使用的所有页面。*分页*是磁盘数据块的内存版本。共享缓冲池缓存从磁盘读取的数据块。该缓冲池减少了从磁盘重新读取数据的需求，从而提高了数据库的运行效率。

每个表和索引都存储为固定大小的页面数组。每个数据块包含多个元组，它们与行相对应。元组可以存储在任何页面中。

共享缓冲池的内存有限。如果新请求需要一个不在内存中的页面，并且没有更多的内存，RDS for PostgreSQL 会移除一个较少使用的页面来容纳请求。移出策略通过时钟扫描算法来实现。

`shared_buffers` 参数确定服务器用于缓存数据的内存量。根据数据库实例的可用内存，默认值设置为 `{DBInstanceClassMemory/32768}` 字节。

### 预写日志 (WAL) 缓冲区
<a name="PostgreSQL.Tuning.concepts.WAL"></a>

*预写日志（WAL）缓冲区*保存 RDS for PostgreSQL 稍后写入持久存储的事务数据。使用 WAL 机制，RDS for PostgreSQL 可以执行以下操作：
+ 发生故障后恢复数据
+ 通过避免频繁写入磁盘来减少磁盘输入/输出

当客户端更改数据时，RDS for PostgreSQL 会将更改写入 WAL 缓冲区。当客户发出 `COMMIT`，WAL 写入器进程将事务数据写入 WAL 文件。

`wal_level` 参数决定向 WAL 写入的信息量，可能的值包括 `minimal`、`replica` 和 `logical` 等。

## RDS for PostgreSQL 中的本地内存
<a name="PostgreSQL.Tuning.concepts.local"></a>

每个后端进程都会为查询处理分配本地内存。

**Topics**
+ [工作内存区域](#PostgreSQL.Tuning.concepts.local.work_mem)
+ [维护工作内存区域](#PostgreSQL.Tuning.concepts.local.maintenance_work_mem)
+ [临时缓冲区](#PostgreSQL.Tuning.concepts.temp)

### 工作内存区域
<a name="PostgreSQL.Tuning.concepts.local.work_mem"></a>

*工作内存区域*保存执行排序和哈希的查询的临时数据。例如，包含 `ORDER BY` 子句的查询执行排序。查询在哈希联接和聚合中使用哈希表。

`work_mem` 参数表示在写入临时磁盘文件之前，内部排序操作和哈希表要使用的内存量，以 MB 为单位。原定设置值为 4MB。可以同时运行多个会话，且每个会话可以并行运行维护操作。出于这个原因，使用的总工作内存可以是 `work_mem` 设置的倍数。

### 维护工作内存区域
<a name="PostgreSQL.Tuning.concepts.local.maintenance_work_mem"></a>

*维护工作内存区域*缓存数据以进行维护操作。这些操作包括 vacuum 操作、创建索引和添加外键。

`maintenance_work_mem` 参数指定维护操作要使用的最大内存量，以 MB 为单位。原定设置值为 64MB。一个数据库会话一次只能运行一个维护操作。

### 临时缓冲区
<a name="PostgreSQL.Tuning.concepts.temp"></a>

*临时缓冲区*缓存每个数据库会话的临时表。

每个会话都根据需要分配临时缓冲区，但不超过您指定的限制。当会话结束时，服务器将清除缓冲区。

`temp_buffers` 参数设置每个会话使用的临时缓冲区的最大数量，以 MB 为单位。默认值为 8 MB。在会话中首次使用临时表之前，您可以更改 `temp_buffers` 值。

# RDS for PostgreSQL 进程
<a name="PostgreSQL.Tuning.concepts.processes"></a>

RDS for PostgreSQL 使用多个进程。

**Topics**
+ [邮件管理员过程](#PostgreSQL.Tuning.concepts.postmaster)
+ [后端进程](#PostgreSQL.Tuning.concepts.backend)
+ [后台进程](#PostgreSQL.Tuning.concepts.vacuum)

## 邮件管理员过程
<a name="PostgreSQL.Tuning.concepts.postmaster"></a>

*邮件管理员进程*是启动 RDS for PostgreSQL 时开始的第一个进程。邮件管理员过程负有以下主要责任：
+ 分流并监控后台进程
+ 接收来自客户端进程的身份验证请求，并在允许数据库为请求提供服务之前对这些请求进行身份验证

## 后端进程
<a name="PostgreSQL.Tuning.concepts.backend"></a>

如果邮件管理员对客户请求进行身份验证，邮件管理员会分流一个新的后端进程，也称为 postgres 进程。一个客户端进程只连接到一个后端进程。客户端进程和后端进程直接通信，而无需邮件管理员过程的干预。

## 后台进程
<a name="PostgreSQL.Tuning.concepts.vacuum"></a>

邮件管理员过程会分流执行不同后端任务的几个进程。其中一些更重要的事项包括：
+ WAL 写入器

  RDS for PostgreSQL 会将 WAL（预写日志记录）缓冲区中的数据写入日志文件。预写日志记录的原则是，在数据库将描述这些更改的日志记录写入磁盘之后，数据库才能将更改写入数据文件。WAL 机制减少了磁盘 I/O，并允许 RDS for PostgreSQL 在出现故障后使用日志恢复数据库。
+ 后台写入器

  此进程会定期将内存缓冲区中的脏（已修改）分页写入数据文件。当后端进程在内存中修改分页时，分页会变脏。
+ Autovacuum 守护进程

  守护进程由以下各项组成：
  + Autovacuum 启动程序
  + Autovacuum 工件进程

  当 Autovacuum 开启时，它会检查包含大量插入的、更新的或删除的元组的表。守护进程要承担以下责任：
  + 恢复或重复使用更新或删除的行占用的磁盘空间
  + 更新计划人员使用的统计数据
  + 防止因事务 ID 重叠而导致旧数据丢失

  Autovacuum 功能自动执行 `VACUUM` 和 `ANALYZE` 命令。`VACUUM` 具有以下变体：标准和完整版。标准 vacuum 与其他数据库操作并行运行。`VACUUM FULL` 需要对您工作所在的表具有专有锁定。因此，它不能与访问同一表的操作并行运行。`VACUUM` 创建了大量的输入/输出流量，这可能会导致其他活动会话的性能不佳。