F.2. amcheck

F.2.1. 函数
F.2.2. 有效地使用amcheck
F.2.3. 修复损坏

amcheck模块允许你验证索引结构的逻辑一致性。 如果结构有效,就不会报错。

该功能验证特定索引表现结构中的各种不变量。 索引扫描和其他重要操作后的访问方法函数的正确性依赖于这些不变量总是保持不变。 例如,某些函数验证是否所有B-Tree页的项都是逻辑顺序的 (例如text类型上的B-Tree索引,索引元组应该是按单词排序的)。 如果这个特定的不变量因为某种原因发生变化, 我们可以预想到受影响页面上的二进制搜索会错误地指导索引扫描, 导致SQL查询的答案错误。

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

只有超级用户可以使用amcheck函数。

F.2.1. 函数

bt_index_check(index regclass) returns void

bt_index_check测试它的目标B-Tree索引遵守各种不变量。 用法示例:

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'
-- 不要检查可能来自另一个会话的临时表:
AND c.relpersistence != 't'
-- 漏掉下面这句函数会报错:
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-Tree 索引遵守各种不变量。由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和所有其他实用命令并发处理底层关系。 请注意,该函数仅在运行时持有锁,并不是整个事务都持有锁。

bt_index_parent_check的附加验证更有可能检测到各种病态情况。 这些情况可能包括被检查的索引使用的B-Tree操作符类执行不正确, 或者假设在底层B-Tree索引访问方式代码中有未被发现的错误。 请注意,与bt_index_check不同, 当启用热备份模式时(也就是在只读物理副本上), 不能使用bt_index_parent_check

F.2.2. 有效地使用amcheck

amcheck可以有效的检测数据页校验和 总是未能捕获的各种类型的失败模式。这些包括:

  • 由于不正确的操作符类实现引起的结构不一致。

    这包括由操作系统排序改变的比较规则引起的问题。 像text这样的可比较类型的数据的比较必须是不可变的 (就像用于B-Tree索引扫描的所有比较必须是不可变的), 这意味着操作系统排序规则决不能改变。虽然很少, 但操作系统排序规则的更新可能会导致这些问题。更常见的情况是, 主服务器和备用服务器之间的排序顺序不一致, 这可能是因为正在使用的主要操作系统版本不一致。 这种不一致通常只会出现在备用服务器上,所以通常只能在备用服务器上检测到。

    如果出现这样的问题,可能不会影响使用受影响的排序规则排序的单独索引, 因为索引的值可能正好拥有相同的绝对顺序,无视表现出来的不一致。 参阅第 23.1 节第 23.2 节 获取关于PostgreSQL如何使用操作系统本地化和排序的详细信息。

  • 由底层的PostgreSQL 访问方法代码或排序代码中的假设未发现的错误导致的损坏。

    索引结构完整性的自动验证在对新的或提议的PostgreSQL 功能进行的一般测试中发挥作用,这些功能可能会导致引入逻辑不一致性。 一个明显的测试策略是在运行标准回归测试时连续调用amcheck函数。 有关运行测试的详细信息,请参见第 32.1 节

  • 未启用校验和时,文件系统或存储子系统故障。

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

  • 内存故障导致的损坏,以及更广泛的内存子系统和操作系统导致的损坏。

    PostgreSQL不能防止可纠正的内存错误, 并假定您将使用使用行业标准纠错码(ECC)或更好保护的RAM进行操作。 然而,ECC内存通常只能抵抗一位错误, 不应该被假定为提供绝对保护来防止导致内存损坏的故障。

通常,amcheck只能证明损坏的存在; 不能证明不存在损坏。

F.2.3. 修复损坏

有关amcheck提出的损坏错误不应该是一个误报。 实际上,amcheck更容易发现软件问题,而不是硬件问题。 在定义的不应该发生情况下,amcheck会引发错误, 因此通常需要对amcheck错误进行仔细的分析。

没有通用的方法修复amcheck检测到的问题。 应该寻找引起不变量变化的根本原因。pageinspect在诊断amcheck检测到的损坏中发挥有用的作用。 REINDEX可能不能有效的修复损坏。