F.2. amcheck

amcheck模块提供的功能可让您验证索引结构的逻辑一致性。如果该结构看起来有效,则不会引发任何错误。

这些函数在特定索引的表示结构中验证了各种“不变式”。索引扫描和其他重要操作背后的访问方法功能的正确性始终取决于这些不变式。例如,某些函数除其他外,验证所有 B-Tree 页面具有“逻辑”Sequences 的项目(例如,对于text上的 B-Tree 索引,索引 Tuples 应按整理的词法 Sequences)。如果该特定不变式无法保持某种状态,则可以预期在受影响的页面上进行二进制搜索会错误地引导索引扫描,从而导致对 SQL 查询的错误答案。

验证使用与索引扫描本身相同的过程执行,该过程可以是用户定义的操作员类代码。例如,B-Tree 索引验证依赖于使用一个或多个 B-Tree 支持功能 1 例程进行的比较。有关操作员类别支持功能的详细信息,请参见Section 37.14.3

amcheck函数只能由超级用户使用。

F.2.1. Functions

  • bt_index_check(index regclass) returns void

    • bt_index_check测试其目标(即 B 树索引)是否尊重各种不变量。用法示例:
test=# SELECT bt_index_check(c.oid), c.relname, c.relpages
FROM pg_index i
JOIN pg_opclass op ON i.indclass[0] = op.oid
JOIN pg_am am ON op.opcmethod = am.oid
JOIN pg_class c ON i.indexrelid = c.oid
JOIN pg_namespace n ON c.relnamespace = n.oid
WHERE am.amname = 'btree' AND n.nspname = 'pg_catalog'
-- Don't check temp tables, which may be from another session:
AND c.relpersistence != 't'
-- Function may throw an error when this is omitted:
AND i.indisready AND i.indisvalid
ORDER BY c.relpages DESC LIMIT 10;
 bt_index_check |             relname             | relpages 
----------------+---------------------------------+----------
                | pg_depend_reference_index       |       43
                | pg_depend_depender_index        |       40
                | pg_proc_proname_args_nsp_index  |       31
                | pg_description_o_c_o_index      |       21
                | pg_attribute_relid_attnam_index |       14
                | pg_proc_oid_index               |       10
                | pg_attribute_relid_attnum_index |        9
                | pg_amproc_fam_proc_index        |        5
                | pg_amop_opr_fam_index           |        5
                | pg_amop_fam_strat_index         |        5
(10 rows)

此示例显示一个会话,该会话执行对数据库“ test”中 10 个最大目录索引的验证。由于未引发错误,因此所有测试的索引在逻辑上似乎都是一致的。自然,可以轻松地将此查询更改为对支持验证的数据库中的每个索引调用bt_index_check

bt_index_check在目标索引及其所属的堆关系上获取AccessShareLock。此锁定模式与通过简单SELECT语句对关系获取的锁定模式相同。 bt_index_check不会验证跨越子/父关系的不变式,也不会验证目标索引与其堆关系是否一致。当在实时生产环境中需要进行常规的轻量级损坏测试时,通常使用bt_index_check可以在验证的彻底性与限制对应用程序性能和可用性的影响之间取得最佳平衡。

  • bt_index_parent_check(index regclass) returns void

    • bt_index_parent_check测试其目标(即 B 树索引)是否尊重各种不变量。 bt_index_parent_check执行的检查是bt_index_check执行的检查的超集。可以将bt_index_parent_check视为bt_index_check的更彻底的变体:与bt_index_check不同,bt_index_parent_check还会检查跨越父/子关系的不变量。但是,它不会验证目标索引与其堆关系是否一致。 bt_index_parent_check遵循一般约定,如果发现逻辑不一致或其他问题,则会引发错误。

bt_index_parent_check在目标索引上需要ShareLock(在堆关系上也需要获取ShareLock)。这些锁可防止通过INSERTUPDATEDELETE命令进行并发数据修改。锁还防止VACUUM以及所有其他 Util 命令同时处理基础关系。请注意,该函数仅在运行时才持有锁,而不是整个事务都持有。

bt_index_parent_check的附加验证更有可能检测各种病理情况。这些情况可能涉及被检查的索引使用的实现不正确的 B-Tree 运算符类,或者可能涉及基础 B-Tree 索引访问方法代码中未发现的错误。请注意,与bt_index_check不同,启用热备模式(即在只读物理副本上)时不能使用bt_index_parent_check

F.2.2. 有效使用 amcheck

amcheck可以有效地检测数据页校验和始终无法捕获的各种故障模式。这些包括:

  • 由错误的操作员类实现导致的结构不一致。

这包括由 os 归类的比较规则更改引起的问题。像text这样的可整理类型的基准的比较必须是不可变的(就像用于 B 树索引扫描的所有比较都必须是不可变的),这意味着 os 排序规则永远不能更改。尽管很少,但对 os 整理规则的更新可能会导致这些问题。更常见的是,暗示了主服务器和备用服务器之间的排序 Sequences 不一致,这可能是因为所使用的主要os 版本不一致。这种不一致通常只会在备用服务器上出现,因此通常只能在备用服务器上检测到。

如果出现这样的问题,它可能不会影响使用受影响的排序规则排序的每个单独索引,这仅仅是因为* indexed *值可能碰巧具有相同的绝对排序,而不管行为不一致。有关 PostgreSQL 如何使用 os 语言环境和排序规则的更多详细信息,请参见Section 23.1Section 23.2

  • 由潜在的 PostgreSQL 访问方法代码或排序代码中未发现的错误引起的损坏。

索引结构完整性的自动验证在新的或建议的 PostgreSQL 功能的常规测试中扮演着重要的角色,这些新功能可能会导致引入逻辑上的不一致。一种明显的测试策略是在运行标准回归测试时连续调用amcheck函数。有关运行测试的详细信息,请参见Section 32.1

  • 根本不会启用校验和发生的文件系统或存储子系统故障。

请注意,如果在访问该块时只有一个共享缓冲区命中,则amcheck会在验证时检查某个共享内存缓冲区中表示的页面。因此,amcheck不一定在验证时检查从文件系统读取的数据。请注意,启用校验和时,amcheck可能会在将损坏的块读入缓冲区时由于校验和失败而引发错误。

  • 由错误的 RAM 或更广泛的内存子系统引起的损坏。

PostgreSQL 不能防止可纠正的内存错误,并且假定您将使用使用行业标准的纠错码(ECC)或更好保护的 RAM 进行操作。但是,ECC 内存通常仅能抵抗单位错误,并且不应假定 ECC 提供绝对保护以防止导致内存损坏的故障。

通常,amcheck仅能证明存在腐败;它不能证明它的缺失。

F.2.3. 修复腐败

amcheck引发的腐败有关的任何错误都不应为假阳性。实际上,amcheck比硬件问题更有可能找到软件错误。根据定义,永远不会发生的情况下amcheck会引发错误,因此经常需要仔细分析amcheck错误。

没有修复amcheck检测到的问题的通用方法。应当寻求对永久违反的根本原因的解释。 pageinspect在诊断amcheck检测到的损坏中可能扮演有用的角色。 REINDEX可能无法有效修复损坏。