三月 19, 2024
摘要:pgfincore
模块提供了一组函数,从 PostgreSQL 管理内存中的页面。
目录
它有一组函数,使用 mincore 来探索缓存,可用于对关系进行底层管理。
描述
使用 PostgreSQL,每个表或索引会被拆分为 1 GB(通常)的段,每个段在内存中分成页面,然后在文件系统上分成块。
通过这些函数,您可以知道关系中的哪些磁盘块以及有多少个磁盘块,在操作系统的页面缓存中。它可以以 VarBit 的形式提供结果,并且可以存储在表中。然后,使用这个表,可以恢复关系中每个块的页面缓存状态,即使到了另一台服务器中,得益于流复制的机制,也依然可以恢复。
其他函数,用于在整个关系(每个段)上设置 POSIX_FADVISE 标志。更有用的状态标志,可能是 WILLNEED 和 DONTNEED,它们分别用于在页面缓存中换入和换出关系中每个段的块。
每个函数都至少需要一个表名或索引名(或 oid)作为参数进行调用,并遍历关系的每个段。
示例
以下是一些用法示例。如果您想了解更多详细信息,请转到函数。
获取关系的当前状态
这可能有用:
redrock=# select * from pgfincore('pgbench_accounts');
relpath | segment | os_page_size | rel_os_pages | pages_mem | group_mem | os_pages_free | databit | pages_dirty | group_dirty
--------------------+---------+--------------+--------------+-----------+-----------+---------------+---------+-------------+-------------
base/11874/16447 | 0 | 4096 | 262144 | 262144 | 1 | 81016 | | 0 | 0
base/11874/16447.1 | 1 | 4096 | 65726 | 65726 | 1 | 81016 | | 0 | 0
(2 rows)
Time: 31.563 ms
在操作系统页面缓冲区中加载表或索引
您可能希望尝试,将表或索引保留在操作系统页面缓存中,或者在执行一条明显的大查询之前预加载表(以减少查询时间)。
为此,只需执行以下查询:
redrock=# select * from pgfadvise_willneed('pgbench_accounts');
relpath | os_page_size | rel_os_pages | os_pages_free
--------------------+--------------+--------------+---------------
base/11874/16447 | 4096 | 262144 | 169138
base/11874/16447.1 | 4096 | 65726 | 103352
(2 rows)
Time: 4462,936 ms
- 列 os_page_size 报告了页面大小为 4KB。
- 列 rel_os_pages 是指定文件的页数。
- 列 os_pages_free 是内存中的空闲页面数(用于缓存)。
对表或索引等对象的操作系统页面缓冲区状态进行快照和还原
您可能希望,将表或索引还原到操作系统页面缓存中,就像进行快照时的状态一样。例如,如果您需要重新启动服务器,那么当 PostgreSQL 启动时,首次执行的查询可能都会变慢,因为 PostgreSQL 和操作系统在各自的缓存中,都没有关于这些首次的查询中涉及的关系页面。
执行一次快照和还原是非常简单的:
-- Snapshot
redrock=# create table pgfincore_snapshot as
select 'pgbench_accounts'::text as relname, *, now() as date_snapshot
from pgfincore('pgbench_accounts',true);
-- Restore
redrock=# select * from pgfadvise_loader('pgbench_accounts', 0, true, true,
(select databit from pgfincore_snapshot
where relname='pgbench_accounts' and segment = 0));
relpath | os_page_size | os_pages_free | pages_loaded | pages_unloaded
------------------+--------------+---------------+--------------+----------------
base/11874/16447 | 4096 | 80867 | 262144 | 0
(1 row)
Time: 35.349 ms
- 列 pages_loaded 报告了已读取到内存的页面数(它们可能已经在内存中)
- 列 pages_unloaded 报告了已从内存中删除的页面数(它们可能尚未在内存中);
概要
pgsysconf(OUT os_page_size bigint, OUT os_pages_free bigint,
OUT os_total_pages bigint)
RETURNS record
pgsysconf_pretty(OUT os_page_size text, OUT os_pages_free text,
OUT os_total_pages text)
RETURNS record
pgfadvise(IN relname regclass, IN fork text, IN action int,
OUT relpath text, OUT os_page_size bigint,
OUT rel_os_pages bigint, OUT os_pages_free bigint)
RETURNS setof record
pgfadvise_willneed(IN relname regclass,
OUT relpath text, OUT os_page_size bigint,
OUT rel_os_pages bigint, OUT os_pages_free bigint)
RETURNS setof record
pgfadvise_dontneed(IN relname regclass,
OUT relpath text, OUT os_page_size bigint,
OUT rel_os_pages bigint, OUT os_pages_free bigint)
RETURNS setof record
pgfadvise_normal(IN relname regclass,
OUT relpath text, OUT os_page_size bigint,
OUT rel_os_pages bigint, OUT os_pages_free bigint)
RETURNS setof record
pgfadvise_sequential(IN relname regclass,
OUT relpath text, OUT os_page_size bigint,
OUT rel_os_pages bigint, OUT os_pages_free bigint)
RETURNS setof record
pgfadvise_random(IN relname regclass,
OUT relpath text, OUT os_page_size bigint,
OUT rel_os_pages bigint, OUT os_pages_free bigint)
RETURNS setof record
pgfadvise_loader(IN relname regclass, IN fork text, IN segment int,
IN load bool, IN unload bool, IN databit varbit,
OUT relpath text, OUT os_page_size bigint,
OUT os_pages_free bigint, OUT pages_loaded bigint,
OUT pages_unloaded bigint)
RETURNS setof record
pgfadvise_loader(IN relname regclass, IN segment int,
IN load bool, IN unload bool, IN databit varbit,
OUT relpath text, OUT os_page_size bigint,
OUT os_pages_free bigint, OUT pages_loaded bigint,
OUT pages_unloaded bigint)
RETURNS setof record
pgfincore(IN relname regclass, IN fork text, IN getdatabit bool,
OUT relpath text, OUT segment int, OUT os_page_size bigint,
OUT rel_os_pages bigint, OUT pages_mem bigint,
OUT group_mem bigint, OUT os_pages_free bigint,
OUT databit varbit, OUT pages_dirty bigint,
OUT group_dirty bigint)
RETURNS setof record
pgfincore(IN relname regclass, IN getdatabit bool,
OUT relpath text, OUT segment int, OUT os_page_size bigint,
OUT rel_os_pages bigint, OUT pages_mem bigint,
OUT group_mem bigint, OUT os_pages_free bigint,
OUT databit varbit, OUT pages_dirty bigint,
OUT group_dirty bigint)
RETURNS setof record
pgfincore(IN relname regclass,
OUT relpath text, OUT segment int, OUT os_page_size bigint,
OUT rel_os_pages bigint, OUT pages_mem bigint,
OUT group_mem bigint, OUT os_pages_free bigint,
OUT databit varbit, OUT pages_dirty bigint,
OUT group_dirty bigint)
RETURNS setof record
函数
pgsysconf
此函数输出操作系统层面的块大小,和操作系统页面缓冲区中的空闲页面数。
redrock=# select * from pgsysconf();
os_page_size | os_pages_free | os_total_pages
--------------+---------------+----------------
4096 | 80431 | 4094174
pgsysconf_pretty
与上面相同,但输出进行了美化。
redrock=# select * from pgsysconf_pretty();
os_page_size | os_pages_free | os_total_pages
--------------+---------------+----------------
4096 bytes | 314 MB | 16 GB
pgfadvise_WILLNEED
此函数在当前关系上设置 WILLNEED 标志。这意味着操作系统将尝试对关系加载尽可能多的页面。主要思想是,在服务器启动时预加载文件,也许是根据缓存命中率,或者根据关系/索引的访问需要。
redrock=# select * from pgfadvise_willneed('pgbench_accounts');
relpath | os_page_size | rel_os_pages | os_pages_free
--------------------+--------------+--------------+---------------
base/11874/16447 | 4096 | 262144 | 80650
base/11874/16447.1 | 4096 | 65726 | 80650
pgfadvise_DONTNEED
此函数在当前关系上设置 DONTNEED 标志。这意味着如果操作系统需要释放一些内存,它将首先换出该文件的页面。主要思想是在文件不再有用时,换出文件(而不是可能更有意义的页面)
redrock=# select * from pgfadvise_dontneed('pgbench_accounts');
relpath | os_page_size | rel_os_pages | os_pages_free
--------------------+--------------+--------------+---------------
base/11874/16447 | 4096 | 262144 | 342071
base/11874/16447.1 | 4096 | 65726 | 408103
pgfadvise_NORMAL
此函数在当前关系上设置 NORMAL 标志。
pgfadvise_SEQUENTIAL
此函数在当前关系上设置 SEQUENTIAL 标志。
pgfadvise_RANDOM
此函数在当前关系上设置 RANDOM 标志。
pgfadvise_loader
此函数允许直接和页面缓存交互。它可以用于,根据用来换入换出的表示页面映射的 varbit,从内存中对页面进行换入/换出。
使用关系 pgbench_accounts,0 号段,任意 varbit 映射:
-- Loading and Unloading
redrock=# select * from pgfadvise_loader('pgbench_accounts', 0, true, true, B'111000');
relpath | os_page_size | os_pages_free | pages_loaded | pages_unloaded
------------------+--------------+---------------+--------------+----------------
base/11874/16447 | 4096 | 408376 | 3 | 3
-- Loading
redrock=# select * from pgfadvise_loader('pgbench_accounts', 0, true, false, B'111000');
relpath | os_page_size | os_pages_free | pages_loaded | pages_unloaded
------------------+--------------+---------------+--------------+----------------
base/11874/16447 | 4096 | 408370 | 3 | 0
-- Unloading
redrock=# select * from pgfadvise_loader('pgbench_accounts', 0, false, true, B'111000');
relpath | os_page_size | os_pages_free | pages_loaded | pages_unloaded
------------------+--------------+---------------+--------------+----------------
base/11874/16447 | 4096 | 408370 | 0 | 3
pgfincore
此函数提供有关文件系统缓存(页面缓存)的信息。
redrock=# select * from pgfincore('pgbench_accounts');
relpath | segment | os_page_size | rel_os_pages | pages_mem | group_mem | os_pages_free | databit | pages_dirty | group_dirty
--------------------+---------+--------------+--------------+-----------+-----------+---------------+---------+-------------+-------------
base/11874/16447 | 0 | 4096 | 262144 | 3 | 1 | 408444 | | 0 | 0
base/11874/16447.1 | 1 | 4096 | 65726 | 0 | 0 | 408444 | | 0 | 0
对于指定的关系,它返回:
- relpath:关系的文件路径
- segment:分析的段号
- os_page_size:单页大小
- rel_os_pages:关系中的总页面数
- pages_mem:在页面缓存中关系的页面总数。(不是 PostgreSQL 中的共享缓冲区,而是操作系统缓存)
- group_mem:相邻的 pages_mem 分组数
- os_page_free:操作系统页面缓存中的空闲页面数
- databit:文件的 varbit 映射,由于其大小,输出没有意义。 使用
pgfincore('pgbench_accounts', true)
激活它。 - pages_dirty:如果定义了 HAVE_FINCORE 常量,并且平台有提供相关信息,像 pages_mem 但只对于脏页面。
- group_dirty:如果定义了 HAVE_FINCORE 常量,并且平台有提供相关信息,像 group_mem 但只对于脏页面。
调试
您可以使用以下错误级别来调试 PgFincore:DEBUG1 和 DEBUG5。
例如:
SET client_min_messages TO debug1; -- debug5 is only usefull to trace each block
要求
PgFincore 需要用到 mincore() 或 fincore() 和 POSIX_FADVISE。
限制
-
当平台不支持 POSIX_FADVISE 时,PgFincore 有一种受限模式。
-
PgFincore 需要 PostgreSQL 版本 >= 8.3
-
PgFincore 不支持 Windows 系统。