10.2. 统计收集器

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

10.2.1. 统计收集器配置

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

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

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

Caution

因为变量 STATS_COMMAND_STRINGSTATS_BLOCK_LEVEL,和 STATS_ROW_LEVEL 缺省时false, 索引实际上缺省配置中不收集任何统计信息。你必须打开其中一个或者 多个才能从统计显示函数中获取有用的结果.

10.2.2. 查看收集到的统计信息

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

在使用统计观察当前活跃性的时候,你必须意识到这些信息 并不是实时更新的.每个独立的服务器进程只是在等待另外一条客户端命令的 时候才向收集器传送新的访问计数;因此正在处理的查询并不影响 显示出来的总数.同样,收集器本身也时最多每 pgstat_stat_interval毫秒 (缺省是 500)发送一次新的总数.因此显示的总数总是落后于实际活动.

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

Table 10-1. 标准统计视图

视图名字描述
pg_stat_activity每个服务器进程一行,显示进程ID,数据库,用户,和当前查询. 只有超级用户看得到当前查询字段;对于其它用户,它显示为 NULL. (请注意因为收集器的报告延迟,当前查询只是对长时间运行的查询 及时更新.)
pg_stat_database每个数据库一行,显示激活的后端的数量,提交的事务总数以及在该 数据库中回卷数目的总数,读取的磁盘块的总数,以及缓冲区命中的总数( 也就是中所需要的块已经在缓冲区中找到,从而避免了读取块的动作).
pg_stat_all_tables当前数据库中每个表一行,里面有顺序扫描和索引扫描的总数, 每种类型的扫描返回的元组的总数以及元组插入,更新,和删除的总数.
pg_stat_sys_tablespg_stat_all_tables一样,只不过只显示系统表.
pg_stat_user_tablespg_stat_all_tables一样,只不过只显示用户表.
pg_stat_all_indexes当前数据库的每个索引一行,包括使用了该索引的索引扫描总数, 索引元组读取的总数以及成功抓取的堆元组的数目(如果有些索引记录指向过期 的堆元组,那么这个数目可能少一些.)
pg_stat_sys_indexespg_stat_all_indexes一样,只不过只包含那些显示为系统表上的索引.
pg_stat_user_indexespg_stat_all_indexes一样,只不过只包含那些显示为用户表上的索引.
pg_statio_all_tables当前数据库中每个表一行,包含从该表中读取的磁盘块总数, 缓冲区命中的总数,在该表上所有索引的磁盘块读取和缓冲区命中总数, 在该表的辅助 TOAST 表(如果存在)上的磁盘块读取和缓冲区命中总数, 以及 TOAST 表的索引的磁盘块读取和缓冲区命中总数.
pg_statio_sys_tablespg_statio_all_tables一样,只不过只显示系统表.
pg_statio_user_tablespg_statio_all_tables一样,只不过只显示用户表.
pg_statio_all_indexes当前数据库中每个索引一行,包含该索引的磁盘块读取和缓冲区命中的 数目.
pg_statio_sys_indexespg_statio_all_indexes一样,只不过只显示系统表.
pg_statio_user_indexespg_statio_all_indexes一样,只不过只显示用户表.
pg_statio_all_sequences当前数据库中每个序列对象一个,包含该序列磁盘读取和缓冲区命中的 数目.
pg_statio_sys_sequencespg_statio_all_sequences一样,只不过只显示系统序列. (准确地说,我们没有定义系统序列,所以这个视图总是空的.)
pg_statio_user_sequencespg_statio_all_sequences一样,只不过只显示用户序列.

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

pg_statio_ 系列视图在判断缓冲的效果的时候特别有用. 在实际磁盘读取远表缓冲命中小的时候,我们就知道这个缓冲基本满足所有 读要求,因此不需要进行系统调用.

其它查看统计的方法可以通过书写使用下层统计访问函数的查询 来设置,这些下层统计访问函数和标准视图里使用的是一样的. 这些函数在Table 10-2 中列出。 就某数据库进行访问的函数接受一个数据库 OID 以标识需要报告哪个数据库. 就某表或者某索引进行访问的函数接受一个表或者索引的 OID (请注意这些函数 只能看到在当前数据库里的表和索引). 就某后端进行访问的函数接受一个后端 ID 号,其范围从一到当前活跃后端的 数目.

Table 10-2. 统计访问函数

函数返回类型描述
pg_stat_get_db_numbackends(oid)integer 数据库中活跃的后端数目.
pg_stat_get_db_xact_commit(oid)bigint 数据库中已提交事务数量.
pg_stat_get_db_xact_rollback(oid)bigint 数据库中回卷的事务数量
pg_stat_get_db_blocks_fetched(oid)bigint 数据库中磁盘块抓取请求总数
pg_stat_get_db_blocks_hit(oid)bigint 为数据库在缓冲区中找到的磁盘块请求总数
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()set of integer 当前活跃后端 ID 的集合 (从 1 到 N,N 时活跃后端的数目). 参阅下面的使用样例.
pg_backend_pid()integer 附着的进程的进程 ID
pg_stat_get_backend_pid(integer)integer 所有后端进程的 PID
pg_stat_get_backend_dbid(integer)oid 后端进程的数据库 ID
pg_stat_get_backend_userid(integer)oid 后端进程的用户 ID
pg_stat_get_backend_activity(integer)text 后端进程的当前查询(如果调用者不是超级用户则为 NULL)
pg_stat_reset()boolean 重置所有当前收集的统计。

注意: blocks_fetched 减去 blocks_hit 就是为该表,索引或者数据库 发出的 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;