24.2. 收集器

PostgreSQL收集器是一个支持收集和汇报服务器活跃性信息的子系统。 目前,这个收集器可以给对表和索引的访问计数,包括磁盘块的数量和独立行的项。 它还可以判断当前其它服务器进程在执行的命令是什么。

24.2.1. 收集器配置

因为收集给查询处理增加了一些过热,所以你可以把系统配置为收集信息,也可以配置为不收集信息。 这个是由配置参数控制的,这些配置参数通常在 postgresql.conf 里设置(参阅 Chapter 17 获取有关设置配置参数的细节)。

要想让收集器运行起来, 参数 stats_start_collector 必须设置为真。 这个设置是缺省设置,也是建议设置,但是如果你对不感兴趣并且想把所有过荷都挤出去, 那么可以把它设置为假。(不过,省下来的东西并不多。) 请注意这个选项在服务器运行的时候并不能改变。

参数 stats_command_stringstats_block_level,和 stats_row_level 控制实际发送给收集器的数量, 因此也决定了会产生多少运行时过热。这些选项分别决定一个服务器进程是否发送它的当前命令字串, 磁盘块层次的访问,以及行层次的访问给收集器。 通常这些参数在 postgresql.conf 中设置, 因此它们适用于所有服务器进程, 但是我们也可以在独立的会话里用 SET 命令把它们打开或者关闭。 (为避免普通用户把它们的活跃性隐藏不给管理员看,只有超级用户允许用 SET 命令修改这些参数。)

注意: 因为参数 stats_command_stringstats_block_level,和 stats_row_level 缺省时false, 索引实际上缺省配置中不收集任何信息。 打开这些配置变量中的一个或多个可以显著增加收机器生成的有用信息的数量,代价是增加了一点运行时开销。

24.2.2. 查看收集到的信息

有一些预定义的视图可以用于显示收集的结果,在 Table 24-1 里列出。另外, 我们可以使用下层的函数制作自己的客户化视图。

在使用观察当前活跃性的时候,你必须意识到这些信息并不是实时更新的。 每个独立的服务器进程只是在准备空闲的时候才向收集器传送新的块和行访问计数; 因此正在处理的查询或者事务并不影响显示出来的总数。 同样,收集器本身也时最多每 PGSTAT_STAT_INTERVAL毫秒 (缺省是 500,除非在制作服务器的时候修改过)发送一次新的报告。因此显示的总数总是落后于实际活动。 当前的查询信息是立即报告给收集器的,但是在其可见之前, 仍然受 PGSTAT_STAT_INTERVAL 的约束。

另外一个需要着重指出的问题是,在请求服务器进程显示任何这些信息的时候, 它首先抓取收集器进程发出的最新的报告。然后它就接着拿这些u乐平台登录注册作为所有视图和函数的快照, 直到它当前的事务的结束。 因此在你当前事务的持续期间内时不会改变的。这是一个特性, 而不是一个毛病,因为这样就允许你在上执行几个查询并且对结果进行相关性的检查而又不用担心这些数字会背着你变化。 但是如果你想看每个查询的新的结果,那么就要记住在任何事务块外面处理这些查询。

Table 24-1. 标准视图

视图名字描述
pg_stat_activity每个服务器进程一行,显示u乐平台登录注册库 OID,u乐平台登录注册库名,进程 ID,用户 OID, 用户名,当前查询和当前查询开始执行的时间, 进程启动的时间和客户端地址以及端口号。 只有在打开 stats_command_string 参数的时候, 才能得到报告当前查询的相关信息的各个字段。 另外,除非检查这些字段的用户是超级用户或者是拥有正在汇报的进程的同一个用户,否则它们显示为空。 (请注意因为收集器的报告延迟,当前查询只是对长时间运行的查询及时更新。)
pg_stat_database每个u乐平台登录注册库一行,显示u乐平台登录注册库 OID,u乐平台登录注册库名,与该u乐平台登录注册库连接的活跃服务器进程数, 提交的事务总数以及在该u乐平台登录注册库中回滚数目的总数, 读取的磁盘块的总数,以及缓冲区命中的总数(也就是所需要的块已经在缓冲区中找到, 从而避免了读取块的动作)。
pg_stat_all_tables当前u乐平台登录注册库中每个表一行(包括 TOAST 的表),表的 OID, 模式和表名字,发起的顺序扫描的总数,顺序扫描抓取的有生u乐平台登录注册行的数目, 发起的索引扫描的总数(属于该表的所有索引),索引扫描抓取的有生u乐平台登录注册行的数目, 以及插入,更新,和删除的行的总数。
pg_stat_sys_tablespg_stat_all_tables 一样,只不过只显示系统表。
pg_stat_user_tablespg_stat_all_tables 一样,只不过只显示用户表。
pg_stat_all_indexes对当前u乐平台登录注册库的每个索引,输入索引所在表和索引的 OID, 模式,表和索引名,包括使用了该索引的索引扫描总数, 索引扫描返回的索引记录的数目,使用该索引的简单索引扫描抓取的有生的表中u乐平台登录注册行数。
pg_stat_sys_indexespg_stat_all_indexes 一样,只不过只包含那些显示为系统表上的索引。
pg_stat_user_indexespg_stat_all_indexes 一样,只不过只包含那些显示为用户表上的索引。
pg_statio_all_tables当前u乐平台登录注册库中每个表一行(包括 TOAST 表),表的 OID,模式和表名, 包含从该表中读取的磁盘块总数,缓冲区命中的次数,在该表上所有索引的磁盘块读取和缓冲区命中总数, 在该表的辅助 TOAST 表(如果存在)上的磁盘块读取和缓冲区命中总数, 以及 TOAST 表的索引的磁盘块读取和缓冲区命中总数。
pg_statio_sys_tablespg_statio_all_tables 一样,只不过只显示系统表。
pg_statio_user_tablespg_statio_all_tables 一样,只不过只显示用户表。
pg_statio_all_indexes当前u乐平台登录注册库中每个索引一行,包含表和索引 OID,模式, 表和索引名,该索引的磁盘块读取和缓冲区命中的数目。
pg_statio_sys_indexespg_statio_all_indexes 一样,只不过只显示系统表。
pg_statio_user_indexespg_statio_all_indexes 一样,只不过只显示用户表。
pg_statio_all_sequences当前u乐平台登录注册库中每个序列对象一行,序列的 OID,模式和序列名, 序列磁盘读取和缓冲区命中的数目。
pg_statio_sys_sequencespg_statio_all_sequences 一样,只不过只显示系统序列。 (目前我们没有定义系统序列,所以这个视图总是空的。)
pg_statio_user_sequencespg_statio_all_sequences 一样,只不过只显示用户序列。

每索引的对于判断哪个索引得到使用以及它们的效果非常有用。

PostgreSQL 8.1 开始, 索引既可以直接使用,也可以通过"位图扫描"使用。 在位图扫描中,多个索引的输出可以通过 AND 或者 OR 规则合并; 所以,在使用索引的时候,很难把独立的堆(表)行抓取和指定的索引抓取界河起来。 因此,位图扫描增大它使用的 pg_stat_all_indexes.idx_tup_read 计数。 并且它还增加为表使用的 pg_stat_all_tables.idx_tup_fetch 计数, 但是它并不会影响 pg_stat_all_indexes.idx_tup_fetch

注意: PostgreSQL 8.1 之前, idx_tup_readidx_tup_fetch 计数实际上总是一样的。 现在即使是不考虑位图扫描,它们也可能是不同的,因为 idx_tup_read 记录从索引检索的记录条目,而 idx_tup_fetch 记录从表中抓取的有生行数; 如果有已经失效的或者是还未提交的行通过索引扫描找出来,后者将会小一些。

pg_statio_ 系列视图在判断缓冲的效果的时候特别有用。 在实际磁盘读取远表缓冲命中小的时候,我们就知道这个缓冲基本满足所有读要求,因此不需要进行内核调用。 但是,这些并未给出所有信息:由于 PostgreSQL 处理磁盘的方式,不在 PostgreSQL 缓冲区缓存的u乐平台登录注册可能仍然驻留在内核的 I/O 缓存中, 因此仍然可能不经过物理读取而抓取。 对获取 PostgreSQL 的 I/O 行为的更多细节感兴趣的用户可以结合使用 PostgreSQL 的收集器和可以分析内核 I/O 处理的操作系统工具来获取更多细节。

其它查看的方法可以通过书写使用下层访问函数的查询来设置,这些下层访问函数和标准视图里使用的是一样的。 这些函数在Table 24-2 中列出。 就某u乐平台登录注册库进行访问的函数接受一个u乐平台登录注册库 OID 为参数来标识需要报告哪个u乐平台登录注册库。 就某表或者某索引进行访问的函数接受一个表或者索引的 OID。 (请注意这些函数只能看到在当前u乐平台登录注册库里的表和索引)。 就某服务器进行访问的函数接受一个服务器进程号,其范围从一到当前活跃服务器的数目。

Table 24-2. 访问函数

函数返回类型描述
pg_stat_get_db_numbackends(oid)integer 处理u乐平台登录注册库的活跃的服务器进程数目。
pg_stat_get_db_xact_commit(oid)bigint u乐平台登录注册库中已提交事务数量。
pg_stat_get_db_xact_rollback(oid)bigint u乐平台登录注册库中回卷的事务数量
pg_stat_get_db_blocks_fetched(oid)bigint u乐平台登录注册库中磁盘块抓取请求总数
pg_stat_get_db_blocks_hit(oid)bigint 为u乐平台登录注册库在缓冲区中找到的磁盘块抓取请求总数
pg_stat_get_numscans(oid)bigint 如果参数是一个表,那么就是进行的顺序扫描的数目, 如果是一个索引,那么就是索引扫描的数目。
pg_stat_get_tuples_returned(oid)bigint 如果参数是一个表,那么就是顺序扫描读取的元组数目, 如果是一个索引,那么就是返回的索引元组的数目
pg_stat_get_tuples_fetched(oid)bigint 如果参数是一个表,那么就是位图扫描抓取的表元行数目, 如果是一个索引,那么就是用简单索引扫描抓取的有效表元组数目
pg_stat_get_tuples_inserted(oid)bigint 插入表中的元组数量
pg_stat_get_tuples_updated(oid)bigint 在表中已更新的元组数量
pg_stat_get_tuples_deleted(oid)bigint 从表中删除的元组数量
pg_stat_get_blocks_fetched(oid)bigint 表或者索引的磁盘块抓取请求的数量
pg_stat_get_blocks_hit(oid)bigint 在缓冲区中找到的表或者索引的磁盘块请求数目
pg_stat_get_backend_idset()setof integer 当前活跃服务器编号的集合(从 1 到活跃后端的数目)。 参阅文本中的使用样例。
pg_backend_pid()integer 附着在当前会话上的服务器进程 ID
pg_stat_get_backend_pid(integer)integer 给出的服务器进程的进程号
pg_stat_get_backend_dbid(integer)oid 指定服务器进程的u乐平台登录注册库 ID
pg_stat_get_backend_userid(integer)oid 指定服务器进程的用户 ID
pg_stat_get_backend_activity(integer)text 服务器进程的当前活跃查询(如果调用者不是超级用户,或者不是与被查询的会话同一个用户, 或者没有打开 stats_command_string 则为 NULL)
pg_stat_get_backend_activity_start(integer)timestamp with time zone 指定服务器进程当前正在执行的查询的起始时间(如果当前用户不是超级用户,或者 不是与被查询的会话同一个用户,或者没有打开 stats_command_string 则为 NULL)
pg_stat_get_backend_start(integer)timestamp with time zone 给出的服务器进程启动的时间,如果当前用户不是超级用户,也不是被查询的后端的同一个用户,则为控。
pg_stat_get_backend_client_addr(integer)inet 连接到给定服务器的客户端的 IP 地址。如果连接是建立在 Unix 域套接字上的,那么为空。 如果当前用户不是超级用户,也不是被查询的会话的使用用户,也为空。
pg_stat_get_backend_client_port(integer)integer 连接到给定服务器的客户端的 IP 端口。如果连接是建立在 Unix 域套接字上的,那么为 -1。 如果当前用户不是超级用户,也不是被查询的会话的使用用户,为空。
pg_stat_reset()boolean 重置所有当前收集的。

注意: blocks_fetched 减去 blocks_hit 就是为该表,索引或者u乐平台登录注册库 发出的 read() 内核调用的数目;不过实际的物理读取的数目通常比较低, 因为还有内核级的缓冲。

函数 pg_stat_get_backend_idset 提供了一个为每个活跃服务器进程生成一行的便捷的方法。 比如,要显示所有服务器的 PID 和它们的当前查询:

SELECT pg_stat_get_backend_pid(s.backendid) AS procpid,
       pg_stat_get_backend_activity(s.backendid) AS current_query
    FROM (SELECT pg_stat_get_backend_idset() AS backendid) AS s;