PostgreSQL教程(三十一):服务器管理(十三)之监控数据库活动

一个数据库管理员常常会疑惑,"系统现在正在做什么?"这一章会讨论如何搞清楚这个问题。

一些工具可以用来监控数据库活动并且分析性能。这一章的大部分都致力于描述PostgreSQL的统计收集器,但是我们也不能忽视常规的 Unix 监控程序,如pstopiostatvmstat。另外,一旦我们发现了一个性能差的查询,可能需要PostgreSQL的EXPAIN命令来进行进一步的调查。

一、标准 Unix 工具

在大部分 Unix 平台上,PostgreSQL会修改由ps报告的命令标题,这样个体服务器进程可以被标识。一个显示样例是

$ ps auxww | grep ^postgres
postgres  15551  0.0  0.1  57536  7132 pts/0    S    18:02   0:00 postgres -i
postgres  15554  0.0  0.0  57536  1184 ?        Ss   18:02   0:00 postgres: background writer
postgres  15555  0.0  0.0  57536   916 ?        Ss   18:02   0:00 postgres: checkpointer
postgres  15556  0.0  0.0  57536   916 ?        Ss   18:02   0:00 postgres: walwriter
postgres  15557  0.0  0.0  58504  2244 ?        Ss   18:02   0:00 postgres: autovacuum launcher
postgres  15558  0.0  0.0  17512  1068 ?        Ss   18:02   0:00 postgres: stats collector
postgres  15582  0.0  0.0  58772  3080 ?        Ss   18:04   0:00 postgres: joe runbug 127.0.0.1 idle
postgres  15606  0.0  0.0  58772  3052 ?        Ss   18:07   0:00 postgres: tgl regression [local] SELECT waiting
postgres  15610  0.0  0.0  58772  3056 ?        Ss   18:07   0:00 postgres: tgl regression [local] idle in transaction

ps的调用方式随不同的平台而变,但是显示的细节都差不多。这个例子来自于一个最近的 Linux 系统)。列在这里的第一个进程是主服务器进程。为它显示的命令参数是当它被启动时使用的那些。接下来的五个进程是由主进程自动启动的后台工作者进程(如果你已经设置系统为不启动统计收集器,"统计收集器"进程将不会出现;同样"自动清理发动"进程也可以被禁用)。剩余的每一个进程都是一个处理一个客户端连接的服务器进程。每个这种进程都会把它的命令行显示设置为这种形式

postgres: user database host activity

在该客户端连接的生命期中,用户、数据库以及(客户端)主机项保持不变,但是活动指示器会改变。活动可以是闲置(即等待一个客户端命令)、在事务中闲置(在一个BEGIN块里等待客户端)或者一个命令类型名,例如SELECT。还有,如果服务器进程正在等待一个其它会话持有的锁, 等待中会被追加到上述信息中。在上面的例子中,我们可以推断:进程 15606 正在等待进程 15610 完成其事务并且因此释放一些锁(进程 15610 必定是阻塞者,因为没有其他活动会话。在更复杂的情况中,可能需要查看pg_locks系统视图来决定谁阻塞了谁)。

如果配置了cluster_name,则集簇的名字 也将会显示在ps的输出中:

$ psql -c 'SHOW cluster_name'
 cluster_name
--------------
 server1
(1 row)

$ ps aux|grep server1
postgres   27093  0.0  0.0  30096  2752 ?        Ss   11:34   0:00 postgres: server1: background writer
...

如果你已经关闭了update_process_title,那么活动指示器将不会被更新,进程标题仅在新进程被启动的时候设置一次。 在某些平台上这样做可以为每个命令节省可观的开销,但在其它平台上却不明显。

提示:

Solaris需要特别的处理。你必需使用/usr/ucb/ps而不是/bin/ps。 你还必需使用两个w标志,而不是一个。另外,你对postgres命令的最初调用必须用一个比服务器进程提供的短的ps状态显示。如果你没有满足全部三个要求,每个服务器进程的ps输出将是原始的postgres命令行。 command line.

二、统计收集器

PostgreSQL的统计收集器是一个支持收集和报告服务器活动信息的子系统。 目前,这个收集器可以对表和索引的访问计数,计数可以按磁盘块和个体行来进行。它还跟踪每个表中的总行数、每个表的清理和分析动作的信息。它也统计调用用户定义函数的次数以及在每次调用中花费的总时间。

PostgreSQL也支持报告有关系统正在干什么的 动态信息,例如当前正在被其他服务器进程执行的命令以及系统中存在哪些其他连接。 这个功能是独立于收集器进程存在的。

2.1. 统计收集配置

因为统计收集给查询执行增加了一些负荷,系统可以被配置为收集或不收集信息。这由配置参数控制,它们通常在postgresql.conf中设置。

参数track_activities允许监控当前被任意服务器进程执行的命令。

参数track_counts控制是否收集关于表和索引访问的统计信息。

参数track_functions启用对用户定义函数使用的跟踪。

参数track_to_timing启用对块读写次数的监控。

通常这些参数被设置在postgresql.conf中,这样它们会应用于所有服务器进程,但是可以在单个会话中使用SET命令打开或关闭它们(为了阻止普通用户对管理员隐藏他们的活动,只有超级用户被允许使用SET来改变这些参数)。

统计收集器通过临时文件将收集到的信息传送给其他PostgreSQL进程。这些文件被存储在名字由stats_temp_directory参数指定的目录中,默认是pg_stat_tmp。为了得到更好的性能,stats_temp_directory可以被指向一个基于 RAM 的文件系统来降低物理 I/O 需求。当服务器被干净地关闭时,一份统计数据的永久拷贝被存储在pg_stat子目录中,这样在服务器重启后统计信息能被保持。当在服务器启动时执行恢复时(例如立即关闭、服务器崩溃以及时间点恢复之后),所有统计计数器会被重置。

2.2. 查看统计信息

表2.2.1中列出了一些预定义视图 可以用来显示系统的当前状态。 表2.2.2中列出了另一些视图可以 显示统计收集的结果。你也可以使用底层统计函数(在 第2.3节中讨论)来建立自定义的视图。

在使用统计信息监控收集到的数据时,你必须了解这些信息并非是实时更新的。每个独立的服务器进程只在进入闲置状态之前才向收集器传送新的统计计数;因此正在进行的查询或事务并不影响显示出来的总数。同样,收集器本身也最多每PGSTAT_STAT_INTERVAL毫秒(缺省为 500ms,除非在编译服务器的时候修改过)发送一 次新的报告。因此显示的信息总是落后于实际活动。但是由track_activities收集的当前查询信息总是最新的。

另一个重点是当一个服务器进程被要求显示任何这些统计信息时,它首先取得收集器进程最近发出的报告并且接着为所有统计视图和函数使用这个快照,直到它的当前事务的结尾。因此只要你继续当前事务,统计数据将会一直显示静态信息。相似地,当任何关于所有会话的当前查询的信息在一个事务中第一次被请求时,这样的信息将被收集。并且在整个事务期间将显示相同的信息。这是一种特性而非缺陷,因为它允许你在该统计信息上执行多个查询并且关联结果而不用担心那些数字会在你不知情的情况下改变。但是如果你希望用每个查询都看到新结果,要确保在任何事务块之外做那些查询。或者,你可以调用pg_stat_clear_snapshot(),那将丢弃当前事务的统计快照(如果有)。下一次对统计性信息的使用将导致获取一个新的快照。

一个事务也可以在视图pg_stat_xact_all_tablespg_stat_xact_sys_tablespg_stat_xact_user_tablespg_stat_xact_user_functions中看到它自己的统计信息(还没有被传送给收集器)。这些数字并不像上面所述的那样行动,相反它们在事务期间持续被更新。

表 2.2.1. 动态统计视图

视图名称 描述
pg_stat_activity 每个服务器进程一行,显示与那个进程的当前活动相关的信息,例如状态和当前查询。详见pg_stat_activity。
pg_stat_replication 每一个 WAL 发送进程一行,显示有关到该发送进程 连接的后备服务器的复制的统计信息。详见 pg_stat_replication。
pg_stat_wal_receiver 只有一行,显示来自 WAL 接收器所连接服务器的有关该接收器的统计信息。详见pg_stat_wal_receiver。
pg_stat_subscription 每个订阅至少一行,显示有关该订阅的工作者的信息。详见pg_stat_subscription。
pg_stat_ssl 每个连接(常规的或者复制)一行,显示在这个连接上使用的SSL的信息。详见pg_stat_ssl。
pg_stat_progress_vacuum 每个运行着VACUUM的后端(包括autovacuum工作者进程)一行,显示当前的进度。详见第4.1节。

表 2.2.2 已收集统计信息的视图

视图名称 描述
pg_stat_archiver 只有一行,显示有关 WAL 归档进程活动的统计信息。详见pg_stat_archiver。
pg_stat_bgwriter 只有一行,显示有关后台写进程的活动的统计信息。详见pg_stat_bgwriter。
pg_stat_database 每个数据库一行,显示数据库范围的统计信息。详见pg_stat_database。
pg_stat_database_conflicts 每个数据库一行,显示数据库范围的统计信息, 这些信息的内容是关于由于与后备服务器的恢复过程 发生冲突而被取消的查询。详见 pg_stat_database_conflicts。
pg_stat_all_tables 当前数据库中每个表一行,显示有关访问指定表的统计信息。详见pg_stat_all_tables。
pg_stat_sys_tables pg_stat_all_tables一样,但只显示系统表。
pg_stat_user_tables pg_stat_all_tables一样,但只显示用户表。
pg_stat_xact_all_tables pg_stat_all_tables相似,但计数动作只在当前事务内发生(还没有 被包括在pg_stat_all_tables和相关视图中)。用于生存和死亡行数量的列以及清理和分析动作在此视图中不出现。
pg_stat_xact_sys_tables pg_stat_xact_all_tables一样,但只显示系统表。
pg_stat_xact_user_tables pg_stat_xact_all_tables一样,但只显示用户表。
pg_stat_all_indexes 当前数据库中的每个索引一行,显示:表OID、索引OID、模式名、表名、索引名、 使用了该索引的索引扫描总数、索引扫描返回的索引记录数、使用该索引的简 单索引扫描抓取的活表(livetable)中数据行数。 当前数据库中的每个索引一行,显示与访问指定索引有关的统计信息。详见pg_stat_all_indexes。
pg_stat_sys_indexes pg_stat_all_indexes一样,但只显示系统表上的索引。
pg_stat_user_indexes pg_stat_all_indexes一样,但只显示用户表上的索引。
pg_statio_all_tables 当前数据库中每个表一行(包括TOAST表),显示:表OID、模式名、表名、 从该表中读取的磁盘块总数、缓冲区命中次数、该表上所有索引的磁盘块读取总数、 该表上所有索引的缓冲区命中总数、在该表的辅助TOAST表(如果存在)上的磁盘块读取总数、 在该表的辅助TOAST表(如果存在)上的缓冲区命中总数、TOAST表的索引的磁盘块读 取总数、TOAST表的索引的缓冲区命中总数。 当前数据库中的每个表一行,显示有关在指定表上 I/O 的统计信息。详见pg_statio_all_tables。
pg_statio_sys_tables pg_statio_all_tables一样,但只显示系统表。
pg_statio_user_tables pg_statio_all_tables一样,但只显示用户表。
pg_statio_all_indexes 当前数据库中每个索引一行,显示:表OID、索引OID、模式名、 表名、索引名、该索引的磁盘块读取总数、该索引的缓冲区命中总数。 当前数据库中的每个索引一行,显示与指定索引上的 I/O 有关的统计信息。详见pg_statio_all_indexespg_statio_all_indexespg_statio_all_indexes
pg_statio_sys_indexes pg_statio_all_indexes一样,但只显示系统表上的索引。
pg_statio_user_indexes pg_statio_all_indexes一样,但只显示用户表上的索引。
pg_statio_all_sequences 当前数据库中每个序列对象一行,显示:序列OID、模式名、序列名、序列的磁盘读取总数、序列的缓冲区命中总数。 当前数据库中的每个序列一行,显示与指定序列上的 I/O 有关的统计信息。详见pg_statio_all_sequences。
pg_statio_sys_sequences pg_statio_all_sequences一样,但只显示系统序列(目前没有定义系统序列,因此这个视图总是为空)。
pg_statio_user_sequences pg_statio_all_sequences一样,但只显示用户序列。
pg_stat_user_functions 对于所有跟踪功能,函数的OID,模式,名称,数量 通话总时间,和自我的时间。自我时间是 在函数本身所花费的时间量,总时间包括 它调用函数所花费的时间。时间值以毫秒为单位。 每一个被跟踪的函数一行,显示与执行该函数有关的统计信息。详见pg_stat_user_functions。
pg_stat_xact_user_functions pg_stat_user_functions相似,但是只统计在当前事务期间的调用(还没有 被包括在pg_stat_user_functions中)。

针对每个索引的统计信息对于判断哪个索引正被使用以及它们的效果特别有用。

pg_statio_系列视图主要用于判断缓冲区的效果。当实际磁盘读取数远小于缓冲区命中时,这个缓冲能满足大部分读请求而无需进行内核调用。但是,这些统计信息并没有给出所有的事情:由于PostgreSQL处理磁盘 I/O 的方式,不在PostgreSQL缓冲区中的数据库仍然驻留在内核的 I/O 缓存中,并且因此可以被再次读取而不需要物理磁盘读取。我们建议希望了解PostgreSQL I/O 行为更多细节的用户将PostgreSQL统计收集器和操作系统中允许观察内核处理 I/O 的工具一起使用。

表 2.2.3. pg_stat_activity 视图

类型 描述
datid oid 这个后端连接到的数据库的OID
datname name 这个后端连接到的数据库的名称
pid integer 这个后端的进程 ID
usesysid oid 登录到这个后端的用户的 OID
usename name 登录到这个后端的用户的名称
application_name text 连接到这个后端的应用的名称
client_addr inet 连接到这个后端的客户端的 IP 地址。如果这个域为空,它表示客户端通过服务器机器上的一个 Unix 套接字连接或者这是一个内部进程(如自动清理)。
client_hostname text 已连接的客户端的主机名,由client_addr的反向 DNS 查找报告。这个域将只对 IP 连接非空,并且只有log_hostname被启用时才会非空。
client_port integer 客户端用以和这个后端通信的 TCP 端口号,如果使用 Unix 套接字则为-1
backend_start timestamp with time zone 这个进程被启动的时间。对客户端后端来说就是客户端连接到服务器的时间。
xact_start timestamp with time zone 这个进程的当前事务被启动的时间,如果没有活动事务则为空。如果当前查询是它的第一个事务,这一列等于query_start
query_start timestamp with time zone 当前活动查询被开始的时间,如果state不是active,这个域为上一个查询被开始的时间
state_change timestamp with time zone state上一次被改变的时间
wait_event_type text 后端正在等待的事件类型,如果不存在则为 NULL。可能的值有: * LWLock:后端正在等待一个轻量级锁。每一个这样的锁保护着共享内存中的一个特殊数据结构。wait_event将含有一个标识该轻量级锁目的的名称(一些锁具有特定的名称,其他是一组具有类似目的的锁中的一部分)。 * Lock:后端正在等待一个重量级锁。重量级锁,也称为锁管理器锁或者简单锁,主要保护 SQL 可见的对象,例如表。不过,它们也被用于确保特定内部操作的互斥,例如关系扩展。wait_event将标识等待的锁的类型。 * BufferPin:服务器进程正在等待访问一个数据缓冲区,而此时没有其他进程正在检查该缓冲区。如果另一个进程持有一个最终从要访问的缓冲区中读取数据的打开的游标,缓冲区 pin 等待可能会被拖延。 * Activity:服务器进程处于闲置状态。这被用于在其主处理循环中等待活动的系统进程。wait_event将标识特定的等待点。 * Extension:服务器进程正在一个扩展模块中等待活动。这一个分类被用于要跟踪自定义等待点的模块。 * Client:服务器进程正在一个套接字上等待来自用户应用的某种活动,并且该服务器预期某种与其内部处理无关的事情发生。wait_event将标识特定的等待点。 * IPC:服务器进程正在等待来自服务器中另一个进程的某种活动。wait_event将标识特定的等待点。 * Timeout:服务器进程正在等待一次超时发生。wait_event将标识特定的等待点。 * IO:服务器进程正在等待一次IO完成。wait_event将标识特定的等待点。
wait_event text 如果后端当前正在等待,则是等待事件的名称,否则为 NULL。详见表2.2.4。
state text 这个后端的当前总体状态。可能的值是: * active:后端正在执行一个查询。 * idle:后端正在等待一个新的客户端命令。 * idle in transaction:后端在一个事务中,但是当前没有正在执行一个查询。 * idle in transaction (aborted):这个状态与idle in transaction相似,不过在该事务中的一个语句导致了一个错误。 * fastpath function call:后端正在执行一个 fast-path 函数。 * disabled:如果在这个后端中track_activities被禁用,则报告这个状态。
backend_xid xid 这个后端的顶层事务标识符(如果存在)。
backend_xmin xid 当前后端的xmin范围。
query text 这个后端最近查询的文本。如果stateactive,这个域显示当前正在执行的查询。在所有其他状态下,它显示上一个被执行的查询。默认情况下,查询文本会被截断至1024个字符,这个值可以通过参数track_activity_query_size更改。
backend_type text 当前后端的类型。可能的类型是 autovacuum launcher, autovacuum worker, logical replication launcher, logical replication worker, parallel worker, background writer, client backend, checkpointer, startup, walreceiver, walsender 以及 walwriter。 除此以外,由扩展注册的后台Worker可能有额外的类型。

pg_stat_activity视图将为每一个服务器进程有一行,显示与该进程的当前活动相关的信息。

注意:

wait_eventstate列是独立的。如果一个后端处于active状态,它可能是也可能不是某个事件上的waiting。如果状态是active并且wait_event为非空,它意味着一个查询正在被执行,但是它被阻塞在系统中某处。

表 2.2.4. wait_event 描述

等待事件类型 等待事件名称 描述
LWLock ShmemIndexLock 正等待在共享内存中查找或者分配空间。
LWLock OidGenLock 正等待分配或者赋予一个 OID。
LWLock XidGenLock 正等待分配或者赋予一个事务 ID。
LWLock ProcArrayLock 正等待在事务结尾得到一个快照或者清除事务 ID。
LWLock SInvalReadLock 正等待从共享无效消息队列中检索或者移除消息。
LWLock SInvalWriteLock 正等待在共享无效消息队列中增加一个消息。
LWLock WALBufMappingLock 正等待在 WAL 缓冲区中替换一个页面。
LWLock WALWriteLock 正等待 WAL 缓冲区被写入到磁盘。
LWLock ControlFileLock 正等待读取或者更新控制文件或创建一个新的 WAL 文件。
LWLock CheckpointLock 正等待执行检查点。
LWLock CLogControlLock 正等待读取或者更新事务状态。
LWLock SubtransControlLock 正等待读取或者更新子事务信息。
LWLock MultiXactGenLock 正等待读取或者更新共享多事务状态。
LWLock MultiXactOffsetControlLock 正等待读取或者更新多事务偏移映射。
LWLock MultiXactMemberControlLock 正等待读取或者更新多事务成员映射。
LWLock RelCacheInitLock 正等待读取或者写入关系缓冲区初始化文件。
LWLock CheckpointerCommLock 正等待管理 fsync 请求。
LWLock TwoPhaseStateLock 正等待读取或者更新预备事务的状态。
LWLock TablespaceCreateLock 正等待创建或者删除表空间。
LWLock BtreeVacuumLock 正等待读取或者更新一个 B-树索引的 vacuum 相关的信息。
LWLock AddinShmemInitLock 正等待管理共享内存中的空间分配。
LWLock AutovacuumLock 自动清理工作者或者启动器正等待更新或者读取自动清理工作者的当前状态。
LWLock AutovacuumScheduleLock 正等待确认选中进行清理的表仍需要清理。
LWLock SyncScanLock 正等待为同步扫描得到一个表上扫描的开始位置。
LWLock RelationMappingLock 正等待更新用来存储目录到文件节点映射的关系映射文件。
LWLock AsyncCtlLock 正等待读取或者更新共享通知状态。
LWLock AsyncQueueLock 正等待读取或者更新通知消息。
LWLock SerializableXactHashLock 正等待检索或者存储有关可序列化事务的信息。
LWLock SerializableFinishedListLock 正等待访问已结束可序列化事务的列表。
LWLock SerializablePredicateLockListLock 正等待在由可序列化事务持有的所列表上执行一个操作。
LWLock OldSerXidLock 正等待读取或者记录冲突的可序列化事务。
LWLock SyncRepLock 正等待读取或者更新有关同步复制的信息。
LWLock BackgroundWorkerLock 正等待读取或者更新后台工作者状态。
LWLock DynamicSharedMemoryControlLock 正等待读取或者更新动态共享内存状态。
LWLock AutoFileLock 正等待更新postgresql.auto.conf文件。
LWLock ReplicationSlotAllocationLock 正等待分配或者释放一个复制槽。
LWLock ReplicationSlotControlLock 正等待读取或者更新复制槽状态。
LWLock CommitTsControlLock 正等待读取或者更新事务提交时间戳。
LWLock CommitTsLock 正等待读取或者更新事务时间戳的最新设置值。
LWLock ReplicationOriginLock 正等待设置、删除或者使用复制源头。
LWLock MultiXactTruncationLock 正等待读取或者阶段多事务信息。
LWLock OldSnapshotTimeMapLock 正等待读取或者更新旧的快照控制信息。
LWLock BackendRandomLock 正等待产生一个随机数。
LWLock LogicalRepWorkerLock 正等待逻辑复制工作者上的动作完成。
LWLock CLogTruncationLock 正等待截断预写式日志或者等待预写式日志截断操作完成。
LWLock clog 正在等地clog (事务状态)缓冲区上的I/O。
LWLock commit_timestamp 正等待提交时间戳缓冲区上的 I/O。
LWLock subtrans 正等待子事务缓冲区上的 I/O。
LWLock multixact_offset 正等待多事务偏移缓冲区上的 I/O。
LWLock multixact_member 正等待多事务成员缓冲区上的 I/O。
LWLock async 正等待 async(通知)缓冲区上的 I/O。
LWLock oldserxid 正等待 oldserxid 缓冲区上的 I/O。
LWLock wal_insert 正等待把 WAL 插入到一个内存缓冲区。
LWLock buffer_content 正等待读取或者写入内存中的一个数据页。
LWLock buffer_io 正等待一个数据页面上的 I/O。
LWLock replication_origin 正等待读取或者更新复制进度。
LWLock replication_slot_io 正等待一个复制槽上的 I/O。
LWLock proc 正等待读取或者更新 fast-path 锁信息。
LWLock buffer_mapping 正等待把一个数据块与缓冲池中的一个缓冲区关联。
LWLock lock_manager 正等待增加或者检查用于后端的锁,或者正等待加入或者退出一个锁定组(并行查询使用)。
LWLock predicate_lock_manager 正等待增加或者检查谓词锁信息。
LWLock parallel_query_dsa 正等待并行查询动态共享内存分配锁。
LWLock tbm 正等待TBM共享迭代器锁。
LWLock parallel_append 在Parallel Append计划执行期间等待选择下一个子计划。
LWLock parallel_hash_join 在Parallel Hash计划执行期间等待分配或交换一块内存或者更新计数器。
Lock relation 正等待获得一个关系上的锁。
Lock extend 正等待扩展一个关系。
Lock page 正等待获得一个关系上的页面的锁。
Lock tuple 正等待获得一个元组上的锁。
Lock transactionid 正等待一个事务结束。
Lock virtualxid 正等待获得一个虚拟 xid 锁。
Lock speculative token 正等待获取一个 speculative insertion lock。
Lock object 正等待获得一个非关系数据库对象上的锁。
Lock userlock 正等待获得一个用户锁。
Lock advisory 正等待获得一个咨询用户锁。
BufferPin BufferPin 正等待在一个缓冲区上加 pin。
Activity ArchiverMain 正在归档进程的主循环中等待。
Activity AutoVacuumMain 正在autovacuum启动器进程的主循环中等待。
Activity BgWriterHibernate 正在后台写入器进程中等待,休眠中。
Activity BgWriterMain 正在后台写入器进程的后台工作者的主循环中等待。
Activity CheckpointerMain 正在检查点进程的主循环中等待。
Activity LogicalApplyMain 正在逻辑应用进程的主循环中等待。
Activity LogicalLauncherMain 正在逻辑启动器进程的主循环中等待。
Activity PgStatMain 正在统计收集器进程的主循环中等待。
Activity RecoveryWalAll 在恢复时等待来自于任意类型来源(本地、归档或流)的WAL。
Activity RecoveryWalStream 在恢复时等待来自于一个流的WAL。
Activity SysLoggerMain 正在系统日志进程的主循环中等待。
Activity WalReceiverMain 正在WAL接收器进程的主循环中等待。
Activity WalSenderMain 正在WAL发送器进程的主循环中等待。
Activity WalWriterMain 正在WAL写入器进程的主循环中等待。
Client ClientRead 正等待从客户端读取数据。
Client ClientWrite 正等待向客户端写入数据。
Client LibPQWalReceiverConnect 正在WAL接收器中等待建立与远程服务器的连接。
Client LibPQWalReceiverReceive 正在WAL接收器中等待从远程服务器接收数据。
Client SSLOpenServer 正在尝试连接期间等待SSL。
Client WalReceiverWaitStart 正等待startup进程发送流复制的初始数据。
Client WalSenderWaitForWAL 正在WAL发送器进程中等待WAL被刷写。
Client WalSenderWriteData 在WAL发送器进程中处理来自WAL接收器的回复时等待任意活动。
Extension Extension 正在一个扩展中等待。
IPC BgWorkerShutdown 正等待后台工作者关闭。
IPC BgWorkerStartup 正等待后台工作者启动。
IPC BtreePage 正等待继续并行B-树扫描所需的页号变得可用。
IPC ClogGroupUpdate 正等待组领袖在事务结束时更新事务状态。
IPC ExecuteGather 在执行Gather节点时等待来自子进程的活动。
IPC Hash/Batch/Allocating 正等待一个选出的Parallel Hash参与者分配哈希表。
IPC Hash/Batch/Electing 正在选出一个Parallel Hash参与者来分配一个哈希表。
IPC Hash/Batch/Loading 正等待其他Parallel Hash参与者完成装载哈希表。
IPC Hash/Build/Allocating 正等待一个选出的Parallel Hash参与者分配初始哈希表。
IPC Hash/Build/Electing 正在选出一个Parallel Hash参与者以分配初始哈希表。
IPC Hash/Build/HashingInner 正等待其他Parallel Hash参与者完成对内关系的哈希操作。
IPC Hash/Build/HashingOuter 正等待其他Parallel Hash参与者完成对外关系的哈希操作。
IPC Hash/GrowBatches/Allocating 正等待一个选出的Parallel Hash参与者分配更多批次。
IPC Hash/GrowBatches/Deciding 正在选出一个Parallel Hash参与者决定未来的批次增长。
IPC Hash/GrowBatches/Electing 正在选出一个Parallel Hash参与者分配更多批次。
IPC Hash/GrowBatches/Finishing 正在等待一个选出的Parallel Hash参与者决定未来的批次增长。
IPC Hash/GrowBatches/Repartitioning 正等待其他Parallel Hash参与者完成重新分区。
IPC Hash/GrowBuckets/Allocating 正等待一个选出的Parallel Hash参与者完成更多桶的分配。
IPC Hash/GrowBuckets/Electing 正在选出一个Parallel Hash参与者分配更多桶。
IPC Hash/GrowBuckets/Reinserting 正等待其他Parallel Hash参与者完成将元组插入到新桶的操作。
IPC LogicalSyncData 正等待逻辑复制的远程服务器发送用于初始表同步的数据。
IPC LogicalSyncStateChange 正等待逻辑复制的远程服务器更改状态。
IPC MessageQueueInternal 正等待其他进程被挂接到共享消息队列。
IPC MessageQueuePutMessage 正等待把一个协议消息写到一个共享消息队列。
IPC MessageQueueReceive 正等待从一个共享消息队列接收字节。
IPC MessageQueueSend 正等待向一个共享消息队列中发送字节。
IPC ParallelBitmapScan 正等待并行位图扫描被初始化。
IPC ParallelCreateIndexScan 正等待并行CREATE INDEX工作者完成堆扫描。
IPC ParallelFinish 正等待并行工作者完成计算。
IPC ProcArrayGroupUpdate 正等待组领袖在事务结束时清除事务ID。
IPC ReplicationOriginDrop 正等待一个复制源头变得不活跃以便被删除。
IPC ReplicationSlotDrop 正等待一个复制槽变得不活跃以便被删除。
IPC SafeSnapshot 正等待一个用于READ ONLY DEFERRABLE事务的快照。
IPC SyncRep 正在同步复制期间等待来自远程服务器的确认。
Timeout BaseBackupThrottle 当有限流活动时在基础备份期间等待。
Timeout PgSleep 正在调用pg_sleep的进程中等待。
Timeout RecoveryApplyDelay 在恢复时等待应用WAL,因为它被延迟了。
IO BufFileRead 正等待从一个缓存的文件中读取。
IO BufFileWrite 正等待向一个缓存的文件中写入。
IO ControlFileRead 正等待从控制文件中读取。
IO ControlFileSync 正等待控制文件到达稳定存储。
IO ControlFileSyncUpdate 正等待对控制文件的更新到达稳定存储。
IO ControlFileWrite 正等待一个对控制文件的写入。
IO ControlFileWriteUpdate 正等待一个写操作更新控制文件。
IO CopyFileRead 正在文件拷贝操作期间等待一个读操作。
IO CopyFileWrite 正在文件拷贝操作期间等待一个写操作。
IO DataFileExtend 正等待一个关系数据文件被扩充。
IO DataFileFlush 正等待一个关系数据文件到达稳定存储。
IO DataFileImmediateSync 正等待一个关系数据文件的立即同步到达稳定存储。
IO DataFilePrefetch 正等待从一个关系数据文件中的一次异步预取。
IO DataFileRead 正等待一次对一个关系数据文件的读操作。
IO DataFileSync 正等待对一个关系数据文件的更改到达稳定存储。
IO DataFileTruncate 正等待一个关系数据文件被截断。
IO DataFileWrite 正等待一次对一个关系数据文件的写操作。
IO DSMFillZeroWrite 等待向一个动态共享内存备份文件中写零字节。
IO LockFileAddToDataDirRead 在向数据目录锁文件中增加一行时等待一个读操作。
IO LockFileAddToDataDirSync 在向数据目录锁文件中增加一行时等待数据到达稳定存储。
IO LockFileAddToDataDirWrite 在向数据目录锁文件中增加一行时等待一个写操作。
IO LockFileCreateRead 在创建数据目录锁文件期间等待读取。
IO LockFileCreateSync 在创建数据目录锁文件期间等待数据到达稳定存储。
IO LockFileCreateWrite 在创建数据目录锁文件期间等待一个写操作。
IO LockFileReCheckDataDirRead 在重新检查数据目录锁文件的过程中等待一个读操作。
IO LogicalRewriteCheckpointSync 在一个检查点期间等待逻辑重写映射到达稳定存储。
IO LogicalRewriteMappingSync 在一次逻辑重写期间等待映射数据到达稳定存储。
IO LogicalRewriteMappingWrite 在一次逻辑重写期间等待对映射数据的写操作。
IO LogicalRewriteSync 正等待逻辑重写映射到达稳定存储。
IO LogicalRewriteWrite 正等待对逻辑重写映射的写操作。
IO RelationMapRead 正等待对关系映射文件的读操作。
IO RelationMapSync 正等待关系映射文件到达稳定存储。
IO RelationMapWrite 正等待对关系映射文件的写操作。
IO ReorderBufferRead 在重排序缓冲区管理期间等待一个读操作。
IO ReorderBufferWrite 在重排序缓冲区管理期间等待一个写操作。
IO ReorderLogicalMappingRead 在重排序缓冲区管理期间等待对一个逻辑映射的读操作。
IO ReplicationSlotRead 正等待对一个复制槽控制文件的读操作。
IO ReplicationSlotRestoreSync 在把一个复制槽控制文件恢复到内存的过程中等待它到达稳定存储。
IO ReplicationSlotSync 正等待一个复制槽控制文件到达稳定存储。
IO ReplicationSlotWrite 正等待对一个复制槽控制文件的写操作。
IO SLRUFlushSync 在检查点或者数据库关闭期间等待SLRU数据到达稳定存储。
IO SLRURead 正等待对一个SLRU页面的读操作。
IO SLRUSync 正等待SLRU数据在一个页面写之后到达稳定存储。
IO SLRUWrite 正等待一个SLRU页面上的写操作。
IO SnapbuildRead 正等待一个序列化历史目录快照的读操作。
IO SnapbuildSync 正等待一个序列化历史目录快照到达稳定存储。
IO SnapbuildWrite 正等待一个序列化历史目录快照的写操作。
IO TimelineHistoryFileSync 正等待一个通过流复制接收到的时间线历史文件到达稳定存储。
IO TimelineHistoryFileWrite 正等待一个通过流复制接收到的时间线历史文件的读操作。
IO TimelineHistoryRead 正等待一个时间线历史文件上的读操作。
IO TimelineHistorySync 正等待一个新创建的时间线历史文件达到稳定存储。
IO TimelineHistoryWrite 正等待一个新创建的时间线历史文件上的写操作。
IO TwophaseFileRead 正等待一个两阶段状态文件的读操作。
IO TwophaseFileSync 正等待一个两阶段状态文件到达稳定存储。
IO TwophaseFileWrite 正等待一个两阶段状态文件的写操作。
IO WALBootstrapSync 在自举期间等待WAL到达稳定存储。
IO WALBootstrapWrite 在自举期间等待一个WAL页面的写操作。
IO WALCopyRead 在通过拷贝一个已有WAL段创建一个新的WAL段时等待一个读操作。
IO WALCopySync 正等待一个通过拷贝已有WAL段创建的新WAL段到达稳定存储。
IO WALCopyWrite 在通过拷贝一个已有WAL段创建一个新的WAL段时等待一个写操作。
IO WALInitSync 正等待一个新初始化的WAL文件到达稳定存储。
IO WALInitWrite 在初始化一个新的WAL文件期间等待一个写操作。
IO WALRead 正等待一次对一个WAL文件的读操作。
IO WALSenderTimelineHistoryRead 在walsender的时间线命令期间等待对一个时间线历史文件的读操作。
IO WALSyncMethodAssign 在指派WAL同步方法时等待数据到达稳定存储。
IO WALWrite 正等待一次对一个WAL文件的写操作。

注意:

对于扩展安装的切片(tranche),这个名称由扩展指定并且会被wait_event显示出来。很有可能在其他后端不知道的情况下,用户在其中一个后端中注册了切片(通过在动态共享内存中分配),那么我们对这种情况会显示extension

下面的例子展示了如何查看等待事件

SELECT pid, wait_event_type, wait_event FROM pg_stat_activity WHERE wait_event is NOT NULL;
 pid  | wait_event_type |  wait_event
------+-----------------+---------------
 2540 | Lock            | relation
 6644 | LWLock          | ProcArrayLock
(2 rows)

表 2.2.5. pg_stat_replication 视图

类型 描述
pid integer 一个 WAL 发送进程的进程 ID
usesysid oid 登录到这个 WAL 发送进程的用户的 OID
usename name 登录到这个 WAL 发送进程的用户的名称
application_name text 连接到这个 WAL 发送进程的应用的名称
client_addr inet 连接到这个 WAL 发送进程的客户端的 IP 地址。 如果这个域为空,它表示该客户端通过服务器机器上的一个 Unix 套接字连接。
client_hostname text 连接上的客户端的主机名,由一次对client_addr 的逆向 DNS 查找报告。这个域将只对 IP 连接非空,并且只有在 log_hostname被启用时非空
client_port integer 客户端用来与这个 WAL 发送进程通讯的 TCP 端口号, 如果使用 Unix 套接字则为-1
backend_start timestamp with time zone 这个进程开始的时间,即客户端是何时连接到这个 WAL 发送进程的
backend_xmin xid 由hot_standby_feedback报告 的这个后备机的xmin水平线。
state text 当前的 WAL 发送进程状态。 可能的值是: * startup:这个WAL发送器正在启动。 * catchup:这个WAL发送器连接的后备机正在追赶主服务器。 * streaming:这个WAL发送器在它连接的后备服务器追上主服务器之后用流传送更改。 * backup:这个WAL发送器正在发送一个备份。 * stopping:这个WAL发送器正在停止。
sent_lsn pg_lsn 在这个连接上发送的最后一个预写式日志的位置
write_lsn pg_lsn 被这个后备服务器写入到磁盘的最后一个预写式日志的位置
flush_lsn pg_lsn 被这个后备服务器刷入到磁盘的最后一个预写式日志的位置
replay_lsn pg_lsn 被重放到这个后备服务器上的数据库中的最后一个预写式日志的位置
write_lag interval 在本地刷写近期的WAL与接收到后备服务器已经写入它(但还没有刷写或者应用)的通知之间流逝的时间。如果这台服务器被配置为一个同步后备,这可以用来计量在提交时synchronous_commit的级别remote_write所导致的延迟。
flush_lag interval 在本地刷写近期的WAL与接收到后备服务器已经写入并且刷写它(但还没有应用)的通知之间流逝的时间。如果这台服务器被配置为一个同步后备,这可以用来计量在提交时synchronous_commit的级别on所导致的延迟。
replay_lag interval 在本地刷写近期的WAL与接收到后备服务器已经写入它、刷写它并且应用它的通知之间流逝的时间。如果这台服务器被配置为一个同步后备,这可以用来计量在提交时synchronous_commit的级别remote_apply所导致的延迟。
sync_priority integer 在基于优先的同步复制中,这台后备服务器被选为同步后备的优先级。在基于规定数量的同步复制中,这个值没有效果。
sync_state text 这一台后备服务器的同步状态。 可能的值是: * async:这台后备服务器是异步的。 * potential:这台后备服务器现在是异步的,但可能在当前的同步后备失效时变成同步的。 * sync:这台后备服务器是同步的。 * quorum:这台后备服务器被当做规定数量后备服务器的候选。

pg_stat_replication视图中将为每一个 WAL 发送进程包含一行,用来显示与该发送进程连接的后备服务器的复制统计信息。 这个视图中只会列出直接连接的后备机,下游后备服务器的信息不包含在此。

pg_stat_replication视图中报告的滞后时间近期的WAL被写入、刷写并且重放以及发送器知道这一切所花的时间的度量。如果远程服务器被配置为一台同步后备,这些时间表示由每一种同步提交级别所带来(或者是可能带来)的提交延迟。对于一台异步后备,replay_lag列是最近的事务变得对查询可见的延迟时间的近似值。如果后备服务器已经完全追上了发送服务器并且没有WAL活动,在短时间内将继续显示最近测到的滞后时间,再然后就会显示为NULL。

对于物理复制会自动测量滞后时间。逻辑解码插件可能会选择性地发出跟踪消息,如果它们没有这样做,跟踪机制将把滞后显示为NULL。

注意:

报告的滞后时间并非按照当前的重放速率该后备还有多久才能追上发送服务器的预测。在新的WAL被生成期间,这样一种系统将显示类似的时间,但是当发送器变为闲置时会显示不同的值。特别是当后备服务器完全追上时,pg_stat_replication显示的是写入、刷写及重放最近报告的WAL位置所花的时间而不是一些用户可能预期的零。这种做法与为近期的写事务测量同步提交和事务可见性延迟的目的一致。为了降低用户预期一种不同的滞后模型带来的混淆,在一个完全重放完的闲置系统上,lag列会在一段比较短的时间后回复成NULL。监控系统应该选择将这种情况表示为缺失数据、零或者继续显示最近的已知值。

表 2.2.6. pg_stat_wal_receiver 视图

类型 描述
pid integer WAL 接收器进程的进程 ID
status text WAL 接收器进程的活动状态
receive_start_lsn pg_lsn WAL 接收器启动时使用的第一个预写式日志位置
receive_start_tli integer WAL 接收器启动时使用的第一个时间线编号
received_lsn pg_lsn 已经接收到并且已经被刷入磁盘的最后一个预写式日志的位置,这个域的初始值是 WAL 接收器启动时使用的第一个日志位置
received_tli integer 已经接收到并且已经被刷入磁盘的最后一个预写式日志的时间线编号,这个域的初始值是 WAL 接收器启动时使用的第一个日志所在的时间线编号
last_msg_send_time timestamp with time zone 从源头 WAL 发送器接收到的最后一个消息的发送时间
last_msg_receipt_time timestamp with time zone 从源头 WAL 发送器接收到的最后一个消息的接收时间
latest_end_lsn pg_lsn 报告给源头 WAL 发送器的最后一个预写式日志位置
latest_end_time timestamp with time zone 报告给源头 WAL 发送器最后一个事务日志位置的时间
slot_name text 这个 WAL 接收器使用的复制槽的名称
sender_host text 这个WAL接收器连接到的PostgreSQL实例的主机。这可以是一个主机名、一个IP地址,如果连接是通过Unix套接字则是一个目录路径(为目录的情况可以被辨别出来,因为路径将总是一个绝对路径并且以/开头)。
sender_port integer 这个WAL接收器连接到的PostgreSQL实例的端口号。
conninfo text 这个 WAL 接收器使用的连接串,安全相关的域会被隐去。

pg_stat_wal_receiver事务只包含一行,它显示了从 WAL 接收器所连接的服务器得到的有关该接收器的统计信息。

表 2.2.7. pg_stat_subscription视图

类型 介绍
subid oid 订阅的OID
subname text 订阅的名称
pid integer 订阅工作者进程的进程ID
relid Oid 工作者正在同步的关系的OID,对于主应用工作者为空
received_lsn pg_lsn 接收到的最后一个预写式日志位置,这个字段的初始值是0
last_msg_send_time timestamp with time zone 从源头WAL发送器接收到的最后一个消息的发送时间
last_msg_receipt_time timestamp with time zone 从源头WAL发送器接收到的最后一个消息的接收时间
latest_end_lsn pg_lsn 最后一个报告给源头WAL发送器的预写式日志位置
latest_end_time timestamp with time zone 报告给源头WAL发送器的最后一个预写式日志位置的时间

每一个订阅的主工作者都在pg_stat_subscription视图中有一行(如果工作者没有运行则PID为空),处理被订阅表的初始数据拷贝操作的工作者还会有额外的行。

表 2.2.8. pg_stat_ssl视图

类型 描述
pid integer 一个后端或者 WAL 发送进程的进程 ID
ssl boolean 如果在这个连接上使用了 SSL 则为真
version text 在用的 SSL 版本,如果这个连接上没有使用 SSL 则为 NULL
cipher text 在用的 SSL 密码的名称,如果这个连接上没有使用 SSL 则为 NULL
bits integer 使用的加密算法中的位数,如果这个连接上没有使用 SSL 则为 NULL
compression boolean 如果使用了 SSL 压缩则为真,否则为假, 如果这个连接上没有使用 SSL 则为 NULL
clientdn text 来自所使用的客户端证书的识别名(DN)域, 如果没有提供客户端证书或者这个连接上没有使用 SSL 则为 NULL。如果 DN 域长度超过 NAMEDATALEN(标准编译 中是 64 个字符),则它会被截断。

pg_stat_ssl视图将为每一个后端或者 WAL 发送进程 包含一行,用来显示这个连接上的 SSL 使用情况。可以把它与 pg_stat_activity或者 pg_stat_replication通过 pid列连接来得到更多有关该连接的细节。

表 2.2.9. pg_stat_archiver视图

类型 描述
archived_count bigint 已被成功归档的 WAL 文件数量
last_archived_wal text 最后一个被成功归档的 WAL 文件名称
last_archived_time timestamp with time zone 最后一次成功归档操作的时间
failed_count bigint 失败的归档 WAL 文件尝试的数量
last_failed_wal text 最后一次失败的归档操作的 WAL 文件名称
last_failed_time timestamp with time zone 最后一次失败的归档操作的时间
stats_reset timestamp with time zone 这些统计信息最后一次被重置的时间

The pg_stat_archiver视图将总是一个单一的行, 该行包含着有关集簇的归档进程的数据。

表 2.2.10. pg_stat_bgwriter视图

类型 描述
checkpoints_timed bigint 已经被执行的计划中检查点的数量
checkpoints_req bigint 已经被执行的请求检查点的数量
checkpoint_write_time double precision 在文件被写入磁盘的检查点处理部分花费的总时间,以毫秒计
checkpoint_sync_time double precision 在文件被同步到磁盘中的检查点处理部分花费的总时间,以毫秒计
buffers_checkpoint bigint 在检查点期间被写的缓冲区数目
buffers_clean bigint 被后台写进程写的缓冲区数目
maxwritten_clean bigint 后台写进程由于已经写了太多缓冲区而停止清洁扫描的次数
buffers_backend bigint 被一个后端直接写的缓冲区数量
buffers_backend_fsync bigint 一个后端不得不自己执行fsync调用的次数(通常即使后端自己进行写操作,后台写进程也会处理这些)
buffers_alloc bigint 被分配的缓冲区数量
stats_reset timestamp with time zone 这些统计信息上次被重置的时间

pg_stat_bgwriter视图将总是只有单独的一行,它包含集簇的全局数据。

表 2.2.11. pg_stat_database视图

类型 描述
datid oid 一个数据库的 OID
datname name 这个数据库的名称
numbackends integer 当前连接到这个数据库的后端数量。这是在这个视图中唯一一个返回反映当前状态值的列。所有其他列返回从上次重置以来积累的值。
xact_commit bigint 在这个数据库中已经被提交的事务的数量
xact_rollback bigint 在这个数据库中已经被回滚的事务的数量
blks_read bigint 在这个数据库中被读取的磁盘块的数量
blks_hit bigint 磁盘块被发现已经在缓冲区中的次数,这样不需要一次读取(这只包括 PostgreSQL 缓冲区中的命中,而不包括在操作系统文件系统缓冲区中的命中)
tup_returned bigint 在这个数据库中被查询返回的行数
tup_fetched bigint 在这个数据库中被查询取出的行数
tup_inserted bigint 在这个数据库中被查询插入的行数
tup_updated bigint 在这个数据库中被查询更新的行数
tup_deleted bigint 在这个数据库中被查询删除的行数
conflicts bigint 由于与恢复冲突而在这个数据库中被取消的查询的数目(冲突只发生在后备服务器上,详见pg_stat_database_conflicts)。
temp_files bigint 在这个数据库中被查询创建的临时文件的数量。所有临时文件都被统计,不管为什么创建这些临时文件(如排序或哈希),并且不管log_temp_files设置。
temp_bytes bigint 在这个数据库中被查询写到临时文件中的数据总量。所有临时文件都被统计,不管为什么创建这些临时文件(如排序或哈希),并且不管log_temp_fileslog_temp_fileslog_temp_files设置。
deadlocks bigint 在这个数据库中被检测到的死锁数
blk_read_time double precision 在这个数据库中后端花费在读取数据文件块的时间,以毫秒计
blk_write_time double precision 在这个数据库中后端花费在写数据文件块的时间,以毫秒计
stats_reset timestamp with time zone 这些统计信息上次被重置的时间

pg_stat_database视图将为集簇中的每一个数据库包含有一行,每一行显示数据库范围的统计信息。

表 2.2.12. pg_stat_database_conflicts视图

类型 描述
datid oid 一个数据库的 OID
datname name 这个数据库的名称
confl_tablespace bigint 这个数据库中由于表空间被删掉而取消的查询数量
confl_lock bigint 这个数据库中由于锁超时而取消的查询数量
confl_snapshot bigint 这个数据库中由于旧快照而取消的查询数量
confl_bufferpin bigint 这个数据库中由于被占用的缓冲区而取消的查询数量
confl_deadlock bigint 这个数据库中由于死锁而取消的查询数量

pg_stat_database_conflicts视图为每一个 数据库包含一行,用来显示数据库范围内由于与后备服务器上的恢复过程 冲突而被取消的查询的统计信息。 这个视图将只包含后备服务器上的信息, 因为冲突会不发生在主服务器上。

表 2.2.13. pg_stat_all_tables视图

类型 描述
relid oid 一个表的 OID
schemaname name 这个表所在的模式的名称
relname name 这个表的名称
seq_scan bigint 在这个表上发起的顺序扫描的次数
seq_tup_read bigint 被顺序扫描取得的活着的行的数量
idx_scan bigint 在这个表上发起的索引扫描的次数
idx_tup_fetch bigint 被索引扫描取得的活着的行的数量
n_tup_ins bigint 被插入的行数
n_tup_upd bigint 被更新的行数(包括 HOT 更新的行)
n_tup_del bigint 被删除的行数
n_tup_hot_upd bigint 被更新的 HOT 行数(即不要求独立索引更新的行更新)
n_live_tup bigint 活着的行的估计数量
n_dead_tup bigint 死亡行的估计数量
n_mod_since_analyze bigint 从这个表最后一次被分析后备修改的行的估计数量
last_vacuum timestamp with time zone 上次这个表被手动清理的时间(不统计VACUUM FULL
last_autovacuum timestamp with time zone 上次这个表被自动清理守护进程清理的时间
last_analyze timestamp with time zone 上次这个表被手动分析的时间
last_autoanalyze timestamp with time zone 上次这个表被自动清理守护进程分析的时间
vacuum_count bigint 这个表已被手工清理的次数(不统计VACUUM FULL
autovacuum_count bigint 这个表已被自动清理守护进程清理的次数
analyze_count bigint 这个表已被手工分析的次数
autoanalyze_count bigint 这个表已被自动清理守护进程分析的次数

pg_stat_all_tables视图将为当前数据库中的每一个表(包括 TOAST 表)包含一行,该行显示与对该表的访问相关的统计信息。pg_stat_user_tablespg_stat_sys_tables视图包含相同的信息,但是被过滤得分别只显示用户和系统表。

表 2.2.14. pg_stat_all_indexes视图

类型 描述
relid oid 这个索引的基表的 OID
indexrelid oid 这个索引的 OID
schemaname name 这个索引所在的模式的名称
relname name 这个索引的基表的名称
indexrelname name 这个索引的名称
idx_scan bigint 在这个索引上发起的索引扫描次数
idx_tup_read bigint 在这个索引上由扫描返回的索引项数量
idx_tup_fetch bigint 被使用这个索引的简单索引扫描取得的活着的表行数量

pg_stat_all_indexes视图将为当前数据库中的每个索引包含一行,该行显示关于对该索引访问的统计信息。pg_stat_user_indexespg_stat_sys_indexes视图包含相同的信息,但是被过滤得只分别显示用户和系统索引。

索引可以被简单索引扫描、"位图"索引扫描以及优化器使用。在一次位图扫描中,多个索引的输出可以被通过 AND 或 OR 规则组合,因此当使用一次位图扫描时难以将取得的个体堆行与特定的索引关联起来。因此,一次位图扫描会增加它使用的索引的pg_stat_all_indexes.idx_tup_read计数,并且为每个表增加pg_stat_all_tables.idx_tup_fetch计数,但是它不影响pg_stat_all_indexes.idx_tup_fetch。如果所提供的常量值不在优化器统计信息记录的范围之内,优化器也会访问索引来检查,因为优化器统计信息可能已经"不新鲜"了。

注意:

即使不用位图扫描,idx_tup_readidx_tup_fetch计数也可能不同,因为idx_tup_read统计从该索引取得的索引项而idx_tup_fetch统计从表取得的或者的行。如果使用该索引取得了任何死亡行或还未提交的行,或者如果通过一次只用索引扫描的方式避免了任何堆获取,后者将较小。

表 2.2.15. pg_statio_all_tables视图

类型 描述
relid oid 一个表的 OID
schemaname name 这个表所在的模式的名称
relname name 这个表的名称
heap_blks_read bigint 从这个表读取的磁盘块数量
heap_blks_hit bigint 在这个表中的缓冲区命中数量
idx_blks_read bigint 从这个表上所有索引中读取的磁盘块数
idx_blks_hit bigint 在这个表上的所有索引中的缓冲区命中数量
toast_blks_read bigint 从这个表的 TOAST 表(如果有)读取的磁盘块数
toast_blks_hit bigint 在这个表的 TOAST 表(如果有)中的缓冲区命中数量
tidx_blks_read bigint 从这个表的 TOAST 表索引(如果有)中读取的磁盘块数
tidx_blks_hit bigint 在这个表的 TOAST 表索引(如果有)中的缓冲区命中数量

pg_statio_all_tables视图将为当前数据库中的每个表(包括 TOAST 表)包含一行,该行显示指定表上有关 I/O 的统计信息。pg_statio_user_tablespg_statio_sys_tables视图包含相同的信息,但是被过滤得分别只显示用户表和系统表。

表 2.2.16. pg_statio_all_indexes视图

类型 描述
relid oid 这个索引的基表的 OID
indexrelid oid 这个索引的 OID
schemaname name 这个索引所在的模式的名称
relname name 这个索引的基表的名称
indexrelname name 这个索引的名称
idx_blks_read bigint 从这个索引读取的磁盘块数
idx_blks_hit bigint 在这个索引中的缓冲区命中数量

pg_statio_all_indexes视图将为当前数据库中的每个索引包含一行,该行显示指定索引上有关 I/O 的统计信息。pg_statio_user_indexespg_statio_sys_indexes视图包含相同的信息,但是被过滤得分别只显示用户索引和系统索引。

表 2.2.17. pg_statio_all_sequences视图

类型 描述
relid oid 一个序列的 OID
schemaname name 这个序列所在的模式的名称
relname name 这个序列的名称
blks_read bigint 从这个序列中读取的磁盘块数
blks_hit bigint 在这个序列中的缓冲区命中数量

pg_statio_all_sequences视图将为当前数据库中的每个序列包含一行,该行显示在指定序列上有关 I/O 的统计信息。

表 2.2.18. pg_stat_user_functions视图

类型 描述
funcid oid 一个函数的 OID
schemaname name 这个函数所在的模式的名称
funcname name 这个函数的名称
calls bigint 这个函数已经被调用的次数
total_time double precision 在这个函数以及它所调用的其他函数中花费的总时间,以毫秒计
self_time double precision 在这个函数本身花费的总时间,不包括被它调用的其他函数,以毫秒计

pg_stat_user_functions视图将为每一个被追踪的函数包含一行,该行显示有关该函数执行的统计信息。track_functions参数控制到底哪些函数被跟踪。

28.2.3. 统计函数

其他查看统计信息的方法是直接使用查询,这些查询使用上述标准视图用到的底层统计信息访问函数。如要了解如函数名等细节,可参考标准视图的定义(例如,在psql中你可以发出\d+ pg_stat_activity)。针对每一个数据库统计信息的访问函数把一个数据库 OID 作为参数来标识要报告哪个数据库。而针对每个表和每个索引的函数要求表或索引 OID。针对每个函数统计信息的函数用一个函数 OID。注意只有在当前数据库中的表、索引和函数才能被这些函数看到。

与统计收集相关的额外函数被列举在表2.2.19中。

表 2.2.19. 额外统计函数

函数 返回类型 描述
pg_backend_pid() integer 处理当前会话的服务器进程的进程 ID
pg_stat_get_activity``(``integer``) setof record 返回具有指定 PID 的后端相关的一个记录,或者在指定NULL的情况下为系统中每一个活动后端返回一个记录。被返回的域是pg_stat_activity视图中的那些域的一个子集。
pg_stat_get_snapshot_timestamp() 带时区的时间戳 返回当前统计信息快照的时间戳
pg_stat_clear_snapshot() void 抛弃当前的统计快照
pg_stat_reset() void 把用于当前数据库的所有统计计数器重置为零(默认要求超级用户权限,但这个函数的 EXECUTE 可以被授予给其他人)。
pg_stat_reset_shared``(text) void 把某些集簇范围的统计计数器重置为零,具体哪些取决于参数(默认要求超级用户权限,但这个函数的 EXECUTE 可以被授予给其他人)。 调用pg_stat_reset_shared('bgwriter')pg_stat_bgwriter 视图中显示的所有计数器清零。调用pg_stat_reset_shared('archiver') 将会把pg_stat_archiver视图中展示的所有计数器清零。
pg_stat_reset_single_table_counters``(oid) void 把当前数据库中用于单个表或索引的统计数据重置为零(默认要求超级用户权限,但这个函数的 EXECUTE 可以被授予给其他人)
pg_stat_reset_single_function_counters``(oid) void 把当前数据库中用于单个函数的统计信息重置为零(默认要求超级用户权限,但这个函数的 EXECUTE 可以被授予给其他人)

pg_stat_get_activitypg_stat_activity视图的底层函数,它返回一个行集合,其中包含有关每个后端进程所有可用的信息。有时只获得该信息的一个子集可能会更方便。在那些情况中,可以使用一组更老的针对每个后端的统计访问函数,这些显示在表2.2.20中。这些访问函数使用一个后端 ID 号,范围从 1 到当前活动后端数目。函数pg_stat_get_backend_idset提供了一种方便的方法为每个活动后端产生一行来调用这些函数。例如,要显示PID以及所有后端当前的查询:

SELECT pg_stat_get_backend_pid(s.backendid) AS pid,
       pg_stat_get_backend_activity(s.backendid) AS query
    FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS s;

表 2.2.20. 针对每个后端的统计函数

函数 返回类型 描述
pg_stat_get_backend_idset() setof integer 当前活动后端 ID 号的集合(从 1 到活动后端数目)
pg_stat_get_backend_activity(integer) text 这个后端最近查询的文本
pg_stat_get_backend_activity_start(integer) timestamp with time zone 最近查询被开始的时间
pg_stat_get_backend_client_addr(integer) inet 该客户端连接到这个后端的 IP 地址
pg_stat_get_backend_client_port(integer) integer 该客户端用来通信的 TCP 端口号
pg_stat_get_backend_dbid(integer) oid 这个后端连接到的数据库的 OID
pg_stat_get_backend_pid(integer) integer 这个后端的进程 ID
pg_stat_get_backend_start(integer) timestamp with time zone 这个进程被开始的时间
pg_stat_get_backend_userid(integer) oid 登录到这个后端的用户的 OID
pg_stat_get_backend_wait_event_type(integer) text 如果后端正在等待,则是等待事件类型的名称,否则为 NULL。详见表2.2.4。
pg_stat_get_backend_wait_event(integer) text 如果后端正在等待,则是等待事件的名称,否则为 NULL。详见表2.2.4。
pg_stat_get_backend_xact_start(integer) timestamp with time zone 当前事务被开始的时间

三、查看锁

监控数据库活动的另外一个有用的工具是pg_locks系统表。这样就允许数据库管理员查看在锁管理器里面未解决的锁的信息。例如,这个功能可以被用于:

  • 查看当前所有未解决的锁、在一个特定数据库中的关系上所有的锁、在一个特定关系上所有的锁,或者由一个特定PostgreSQL会话持有的所有的锁。

  • 判断当前数据库中带有最多未授予锁的关系(它很可能是数据库客户端的竞争源)。

  • 判断锁竞争给数据库总体性能带来的影响,以及锁竞争随着整个数据库流量的变化范围。

四、进度报告

PostgreSQL有能力在命令执行期间报告特定命令的进度。当前,唯一一种支持进度报告的命令是VACUUM。这在未来可能会被扩充。

4.1. VACUUM进度报告

只要VACUUM正在运行,每一个当前正在清理的后端(包括autovacuum工作者进程)在pg_stat_progress_vacuum视图中都会有一行。下面的表描述了将被报告的信息并且提供了如何解释它们的信息。进度报告当前不支持VACUUM FULL,运行着VACUUM FULL的后端将不会在这个视图中列出。

表 4.1.1. pg_stat_progress_vacuum视图

类型 描述
pid integer 后端的进程ID。
datid oid 这个后端连接的数据库的OID。
datname name 这个后端连接的数据库的名称。
relid oid 被vacuum的表的OID。
phase text vacuum的当前处理阶段。请参考表4.1.2。
heap_blks_total bigint 该表中堆块的总数。这个数字在扫描开始时报告,之后增加的块将不会(并且不需要)被这个VACUUM访问。
heap_blks_scanned bigint 被扫描的堆块数量。由于可见性映射被用来优化扫描,一些块将被跳过而不做检查,被跳过的块会被包括在这个总数中,因此当清理完成时这个数字最终将会等于heap_blks_total。仅当处于扫描堆阶段时这个计数器才会前进。
heap_blks_vacuumed bigint 被清理的堆块数量。除非表没有索引,这个计数器仅在处于清理堆阶段时才会前进。不包含死亡元组的块会被跳过,因此这个计数器可能有时会向前跳跃一个比较大的增量。
index_vacuum_count bigint 已完成的索引清理周期数。
max_dead_tuples bigint 在需要执行一个索引清理周期之前我们可以存储的死亡元组数,取决于maintenance_work_mem。
num_dead_tuples bigint 从上一个索引清理周期以来收集的死亡元组数。

表 4.1.2. VACUUM的阶段

阶段 描述
初始化 VACUUM正在准备开始扫描堆。这个阶段应该很简短。
扫描堆 VACUUM正在扫描堆。如果需要,它将会对每个页面进行修建以及碎片整理,并且可能会执行冻结动作。heap_blks_scanned列可以用来监控扫描的进度。
清理索引 VACUUM当前正在清理索引。如果一个表拥有索引,那么每次清理时这个阶段会在堆扫描完成后至少发生一次。如果maintenance_work_memmaintenance_work_memmaintenance_work_mem不足以存放找到的死亡元组,则每次清理时会多次清理索引。
清理堆 VACUUM当前正在清理堆。清理堆与扫描堆不是同一个概念,清理堆发生在每一次清理索引的实例之后。如果heap_blks_scanned小于heap_blks_total,系统将在这个阶段完成之后回去扫描堆;否则,系统将在这个阶段完成后开始清理索引。
清除索引 VACUUM当前正在清除索引。这个阶段发生在堆被完全扫描并且对堆和索引的所有清理都已经完成以后。
截断堆 VACUUM正在截断堆,以便把关系尾部的空页面返还给操作系统。这个阶段发生在清除完索引之后。
执行最后的清除 VACUUM在执行最终的清除。在这个阶段中,VACUUM将清理空闲空间映射、更新pg_class中的统计信息并且将统计信息报告给统计收集器。当这个阶段完成时,VACUUM也就结束了。

五、动态追踪

PostgreSQL提供了功能来支持数据库服务器的动态追踪。这样就允许在代码中的特 定点上调用外部工具来追踪执行过程。

一些探针或追踪点已经被插入在源代码中。这些探针的目的是被数据库开发者和管理员使用。默认情况下,探针不被编译到PostgreSQL中;用户需要显式地告诉配置脚本使得探针可用。

目前,在写本文当时DTrace已被支持,它在 Solaris、macOS、FreeBSD、NetBSD 和 Oracle Linux 上可用。Linux 的SystemTap项目提供了一种可用的 DTrace 等价物。支持其他动态追踪工具在理论上可以通过改变src/include/utils/probes.h中的宏定义实现。

5.1. 动态追踪的编译

默认情况下,探针是不可用的,因此你将需要显式地告诉配置脚本让探针在PostgreSQL中可用。要包括 DTrace 支持,在配置时指定--enable-dtrace

5.2. 内建探针

如表5.2.1所示,源代码中提供了一些标准探针。表5.2.2显式了在探针中使用的类型。当然,可以增加更多探针来增强PostgreSQL的可观测性。

表 5.2.1. 内建 DTrace 探针

名称 参数 描述
transaction-start (LocalTransactionId) 在一个新事务开始时触发的探针。arg0 是事务 ID。
transaction-commit (LocalTransactionId) 在一个事务成功完成时触发的探针。arg0 是事务 ID。
transaction-abort (LocalTransactionId) 当一个事务失败完成时触发的探针。arg0 是事务 ID。
query-start (const char *) 当一个查询的处理被开始时触发的探针。arg0 是查询字符串。
query-done (const char *) 当一个查询的处理完成时触发的探针。arg0 是查询字符串。
query-parse-start (const char *) 当一个查询的解析被开始时触发的探针。arg0 是查询字符串。
query-parse-done (const char *) 当一个查询的解析完成时触发的探针。arg0 是查询字符串。
query-rewrite-start (const char *) 当一个查询的重写被开始时触发的探针。arg0 是查询字符串。
query-rewrite-done (const char *) 当一个查询的重写完成时触发的探针。arg0 是查询字符串。
query-plan-start () 当一个查询的规划被开始时触发的探针。
query-plan-done () 当一个查询的规划完成时触发的探针。
query-execute-start () 当一个查询的执行被开始时触发的探针。
query-execute-done () 当一个查询的执行完成时触发的探针。
statement-status (const char *) 任何时候当服务器进程更新它的pg_stat_activity.status时触发的探针。arg0 是新的状态字符串。
checkpoint-start (int) 当一个检查点被开始时触发的探针。arg0 保持逐位标志来区分不同的检查点类型,例如关闭(shutdown)、立即(immediate)或强制(force)。
checkpoint-done (int, int, int, int, int) 当一个检查点完成时触发的探针(检查点处理过程中序列中列出的下一个触发的探针)。arg0 是要写的缓冲区数量。arg1 是缓冲区的总数。arg2、arg3 和 arg4 分别包含了增加、删除和循环回收的 WAL 文件的数量。
clog-checkpoint-start (bool) 当一个检查点的 CLOG 部分被开始时触发的探针。arg0 为真表示正常检查点,为假表示关闭检查点。
clog-checkpoint-done (bool) 当一个检查点的 CLOG 部分完成时触发的探针。arg0 的含义与clog-checkpoint-start中相同。
subtrans-checkpoint-start (bool) 当一个检查点的 SUBTRANS 部分被开始时触发的探针。arg0 为真表示正常检查点,为假表示关闭检查点。
subtrans-checkpoint-done (bool) 当一个检查点的 SUBTRANS 部分完成时触发的探针。arg0 的含义与subtrans-checkpoint-start中相同。
multixact-checkpoint-start (bool) 当一个检查点的 MultiXact 部分被开始时触发的探针。arg0 为真表示正常检查点,为假表示关闭检查点。
multixact-checkpoint-done (bool) 当一个检查点的 MultiXact 部分完成时触发的探针。arg0 的含义与multixact-checkpoint-start中相同。
buffer-checkpoint-start (int) 当一个检查点的写缓冲区部分被开始时触发的探针。arg0 保持逐位标志来区分不同的检查点类型,例如关闭(shutdown)、立即(immediate)或强制(force)。
buffer-sync-start (int, int) 当我们在检查点期间开始写脏缓冲区时(在标识哪些缓冲区必须被写之后)触发的探针。arg0 是缓冲区总数,arg1 是当前为脏并且需要被写的缓冲区数量。
buffer-sync-written (int) 在检查点期间当每个缓冲区被写完之后触发的探针。arg0 是缓冲区的 ID。
buffer-sync-done (int, int, int) 当所有脏缓冲区被写之后触发的探针。arg0 是缓冲区总数。arg1 是检查点进程实际写的缓冲区数量。arg2 是期望写的数目(buffer-sync-start的 arg1);arg1 和 arg2 的任何的不同反映在该检查点期间有其他进程刷写了缓冲区。
buffer-checkpoint-sync-start () 在脏缓冲区被写入到内核之后并且在开始发出 fsync 请求之前触发的探针。
buffer-checkpoint-done () 当同步缓冲区到磁盘完成时触发的探针。
twophase-checkpoint-start () 当一个检查点的两阶段部分被开始时触发的探针。
twophase-checkpoint-done () 当一个检查点的两阶段部分完成时触发的探针。
buffer-read-start (ForkNumber, BlockNumber, Oid, Oid, Oid, int, bool) 当一次缓冲区读被开始时触发的探针。arg0 和 arg1 包含该页的分叉号和块号(如果这是一次关系扩展请求,arg1 为 -1)。arg2、arg3 和 arg4 包含表空间、数据库和关系 OID 用以识别该关系。对一个本地缓冲区,arg5 是创建临时关系的后端的 ID;对于一个共享缓冲区,arg5 是 InvalidBackendId(-1)。表示真,对共享缓冲区表示假。 arg6 为真表示一次关系扩展请求,为假表示正常读。
buffer-read-done (ForkNumber, BlockNumber, Oid, Oid, Oid, int, bool, bool) 当一次缓冲区读完成时触发的探测器。arg0 和 arg1 包含该页的分叉号和块号(如果这是一次关系扩展请求,arg1 现在包含新增加块的块号)。arg2、arg3 和 arg4 包含表空间、数据库和关系 OID 用以识别该关系。对一个本地缓冲区,arg5 是创建临时关系的后端的 ID;对于一个共享缓冲区,arg5 是 InvalidBackendId(-1)。表示真,对共享缓冲区表示假。 arg6 为真表示一次关系扩展请求,为假表示正常读。arg7 为真表示在池中找到该缓冲区,为假表示没有找到。
buffer-flush-start (ForkNumber, BlockNumber, Oid, Oid, Oid) 在发出对一个共享缓冲区的任意写请求之前触发的探针。arg0 和 arg1 包含该页的分叉号和块号。arg2、arg3 和 arg4 包含表空间、数据库和关系 OID 用以识别该关系。
buffer-flush-done (ForkNumber, BlockNumber, Oid, Oid, Oid) 当一个写请求完成时触发的探针(注意这只反映传递数据给内核的时间,它通常并没有实际地被写入到磁盘)。参数和buffer-flush-start的相同。
buffer-write-dirty-start (ForkNumber, BlockNumber, Oid, Oid, Oid) 当一个服务器进程开始写一个脏缓冲区时触发的探针(如果这经常发生,表示shared_buffers太小,或需要调整后台写入器的控制参数)。arg0 和 arg1 包含该页的分叉号和块号。arg2、arg3 和 arg4 包含表空间、数据库和关系 OID 用以识别该关系。
buffer-write-dirty-done (ForkNumber, BlockNumber, Oid, Oid, Oid) 当一次脏缓冲区写完成时触发的探针。参数与buffer-write-dirty-start相同。
wal-buffer-write-dirty-start () 当一个服务器进程因为没有可用 WAL 缓冲区空间开始写一个脏 WAL 缓冲区时触发的探针(如果这经常发生,表示wal_buffers太小)。
wal-buffer-write-dirty-done () 当一次脏 WAL 缓冲区完成时触发的探针。
wal-insert (unsigned char, unsigned char) 当一个 WAL 记录被插入时触发的探针。arg0 是该记录的资源管理者(rmid)。arg1 包含 info 标志。
wal-switch () 当请求一次 WAL 段切换时触发的探针。
smgr-md-read-start (ForkNumber, BlockNumber, Oid, Oid, Oid, int) 当开始从一个关系读取一块时触发的探针。arg0 和 arg1 包含该页的分叉号和块号。arg2、arg3 和 arg4 包含表空间、数据库和关系 OID 用以识别该关系。对一个本地缓冲区,arg5 是创建临时关系的后端的 ID;对于一个共享缓冲区,arg5 是InvalidBackendId(-1)。
smgr-md-read-done (ForkNumber, BlockNumber, Oid, Oid, Oid, int, int, int) 当一次块读取完成时触发的探针。arg0 和 arg1 包含该页的分叉号和块号。arg2、arg3 和 arg4 包含表空间、数据库和关系 OID 用以识别该关系。对一个本地缓冲区,arg5 是创建临时关系的后端的 ID;对于一个共享缓冲区,arg5 是InvalidBackendId(-1)。arg6 是实际读取的字节数,而 arg7 是请求读取的字节数(如果两者不同就意味着麻烦)。
smgr-md-write-start (ForkNumber, BlockNumber, Oid, Oid, Oid, int) 当开始向一个关系中写入一个块时触发的探针。arg0 和 arg1 包含该页的分叉号和块号。arg2、arg3 和 arg4 包含表空间、数据库和关系 OID 用以识别该关系。对一个本地缓冲区,arg5 是创建临时关系的后端的 ID;对于一个共享缓冲区,arg5 是InvalidBackendId(-1)。
smgr-md-write-done (ForkNumber, BlockNumber, Oid, Oid, Oid, int, int, int) 当一个块写操作完成时触发的探针。arg0 和 arg1 包含该页的分叉号和块号。arg2、arg3和arg4 包含表空间、数据库和关系 OID来标识该关系。对于一个本地缓冲区,arg5 是创建临时关系的后端 ID;对于一个共享缓冲区,arg5 是InvalidBackendId(-1)。arg6 是实际写的字节数,而 arg7 是要求写的字节数(如果这两者不同,则意味着麻烦)。
sort-start (int, bool, int, int, bool, int) 当一次排序操作开始时触发的探针。arg0 指示是堆排序、索引排序或数据排序。arg1 为真表示唯一值强制。arg2 是键列的数目。arg3 是允许使用的工作内存数(以千字节计)。如果要求随机访问排序结果,那么 arg4 为真。arg5为0时表示串行,为1时表示并行工作者,为2时表示并行领袖。
sort-done (bool, long) 当一次排序完成时触发的探针。arg0 为真表示外排序,为假表示内排序。arg1 是用于一次外排序的磁盘块的数目,或用于一次内排序的以千字节计的内存。
lwlock-acquire (char *, LWLockMode) 当成功获得一个 LWLock 时触发的探针。 arg0 是该 LWLock 所在的切片(Tranche)。 arg1 所请求的锁模式,是排他或共享。
lwlock-release (char *) 当一个 LWLock 被释放时(但是注意还没有唤醒任何一个被释放的等待者)触发的探针。 arg0 是该 LWLock 所在的切片(Tranche)。
lwlock-wait-start (char *, LWLockMode) 当一个 LWLock不是当即可用并且一个服务器进程因此开始等待该锁变为可用时触发的探针。 arg0 是该 LWLock 所在的切片(Tranche)。 arg1 请求的锁模式,是排他或共享。
lwlock-wait-done (char *, LWLockMode) 当一个进程从对一个 LWLock 的等待中被释放时(它实际还没有得到该锁)时触发的探针。arg0 是该 LWLock 所在的切片(Tranche)。 arg1 所请求的锁模式,是排他或共享。
lwlock-condacquire (char *, LWLockMode) 当调用者指定无需等待而成功获得一个 LWLock 时触发的探针。arg0 是该 LWLock 所在的切片(Tranche)。 arg1 所请求的锁模式,是排他或共享。
lwlock-condacquire-fail (char *, LWLockMode) 当调用者指定无需等待而没有成功获得一个 LWLock 时触发的探针。arg0 是该 LWLock 所在的切片(Tranche)。 arg1 所请求的锁模式,是排他或共享。
lock-wait-start (unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, LOCKMODE) 当一个重量级锁(lmgr锁)的请求由于锁不可用开始等待时触发的探针。arg0 到 arg3 是标识被锁定对象的标签域。arg4 指示被锁对象的类型。arg5 表示被请求的锁类型。
lock-wait-done (unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, LOCKMODE) 当一个重量级锁(lmgr 锁)的请求结束等待时(即已经得到锁)触发的探针。参数与lock-wait-start一样。
deadlock-found () 当死锁检测器发现死锁时触发的探针。

表 5.2.2. 定义用在探针参数中的类型

类型 定义
LocalTransactionId unsigned int
LWLockMode int
LOCKMODE int
BlockNumber unsigned int
oid unsigned int
ForkNumber int
bool char

5.3. 使用探针

下面的例子展示了一个分析系统中事务计数的 DTrace 脚本,可以用来代替一次性能测试之前和之后的pg_stat_database快照:

#!/usr/sbin/dtrace -qs

postgresql$1:::transaction-start
{
      @start["Start"] = count();
      self->ts  = timestamp;
}

postgresql$1:::transaction-abort
{
      @abort["Abort"] = count();
}

postgresql$1:::transaction-commit
/self->ts/
{
      @commit["Commit"] = count();
      @time["Total time (ns)"] = sum(timestamp - self->ts);
      self->ts=0;
}

当被执行时,该例子 D 脚本给出这样的输出:

# ./txn_count.d `pgrep -n postgres` or ./txn_count.d <PID>
^C

Start                                          71
Commit                                         70
Total time (ns)                        2312105013

注意:

SystemTap 为追踪脚本使用一个不同于 DTrace 的标记,但是底层的探针是兼容的。值得注意的是,在这样写的时候,SystemTap 脚本必须使用双下划线代替连字符来引用探针名。在未来的 SystemTap 发行中这很可能会被修复。

你应该记住,DTrace 脚本需要细心地编写和调试,否则被收集的追踪信息可能会毫无意义。在大部分发现问题的情况中,它就是发生问题的部件,而不是底层系统。当讨论使用动态追踪发现的信息时,一定要封闭使用的脚本来允许这些以便被检查和讨论。

5.4. 定义新探针

开发者可以在代码中任意位置定义新的探针,当然这要重新编译之后才能生效。下面是插入新探针的步骤:

  1. 决定探针名称以及探针可用的数据

  2. 把该探针定义加入到src/backend/utils/probes.d

  3. 如果pg_trace.h还不存在于包含该探针点的模块中,包括它,并且在源代码中期望的位置插入TRACE_POSTGRESQL探针宏

  4. 重新编译并验证新探针是可用的

例子:. 这里是一个如何增加一个探针来用事务 ID 追踪所有新事务的例子。

  1. 决定探针将被命名为transaction-start并且需要一个LocalTransactionId类型的参数

  2. 将该探针定义加入到src/backend/utils/probes.d

    probe transaction__start(LocalTransactionId);

注意探针名字中双下划线的使用。在一个使用探针的 DTrace 脚本中,双下划线需要被替换为一个连字符,因此 ,对用户而言transaction-start是文档名。

3.在编译时,transaction__start被转换成一个宏调用TRACE_POSTGRESQL_TRANSACTION_START(注意这里是单下划线),可以通过包括头文件pg_trace.h获得。将宏调用加入到源代码中的合适位置。在这种情况下,看起来类似:

TRACE_POSTGRESQL_TRANSACTION_START(vxid.localTransactionId);

4.在重新编译和运行新的二进制文件之后,通过运行下面的 DTrace 命令来检查新增的探针是否可用。你应该看到类似下面的输出:

# dtrace -ln transaction-start
   ID    PROVIDER          MODULE           FUNCTION NAME
18705 postgresql49878     postgres     StartTransactionCommand transaction-start
18755 postgresql49877     postgres     StartTransactionCommand transaction-start
18805 postgresql49876     postgres     StartTransactionCommand transaction-start
18855 postgresql49875     postgres     StartTransactionCommand transaction-start
18986 postgresql49873     postgres     StartTransactionCommand transaction-start

向C代码中添加追踪宏时,有一些事情需要注意:

  • 需要小心的是,为探针参数指定的数据类型要匹配宏中使用的变量的数据类型,否则会发生编译错误。

  • 在大多数平台上,如果用--enable-dtrace编译了PostgreSQL,无论何时当控制经过一个追踪宏时,都会评估该宏的参数,即使没有进行追踪也会这样做。通常不需要担心你是否只在报告一些局部变量的值。但要注意将开销大的函数调用放置在这些参数中。如果你需要这样做,考虑通过检查追踪是否真的被启用来保护该宏:

    if (TRACE_POSTGRESQL_TRANSACTION_START_ENABLED())
    TRACE_POSTGRESQL_TRANSACTION_START(some_function(...));

  • 每个追踪宏有一个对应的ENABLED宏。

相关推荐
Rookie也要加油3 分钟前
01_SQLite
数据库·sqlite
liuxin334455667 分钟前
教育技术革新:SpringBoot在线教育系统开发
数据库·spring boot·后端
看山还是山,看水还是。1 小时前
MySQL 管理
数据库·笔记·mysql·adb
fishmemory7sec1 小时前
Koa2项目实战2(路由管理、项目结构优化)
数据库·mongodb·koa
momo小菜pa1 小时前
【MySQL 09】表的内外连接
数据库·mysql
Jasonakeke1 小时前
【重学 MySQL】四十九、阿里 MySQL 命名规范及 MySQL8 DDL 的原子化
数据库·mysql
程序猿小D1 小时前
第二百六十九节 JPA教程 - JPA查询OrderBy两个属性示例
java·开发语言·数据库·windows·jpa
小宇成长录2 小时前
Mysql:数据库和表增删查改基本语句
数据库·mysql·数据库备份
团儿.2 小时前
解锁MySQL高可用新境界:深入探索MHA架构的无限魅力与实战部署
数据库·mysql·架构·mysql之mha架构
程序猿小D3 小时前
第二百六十七节 JPA教程 - JPA查询AND条件示例
java·开发语言·前端·数据库·windows·python·jpa