F.2. amcheck

Модуль amcheck предоставляет функции, позволяющие проверять логическую целостность структуры индексов. Если нарушения структуры не обнаруживаются, эти функции отрабатывают без ошибок.

Эти функции проверяют различные инварианты в структуре представления определённых индексов. Правильность работы функций методов доступа, стоящих за сканированием индекса и другими важными операциями, зависит от всегда соблюдаемых инвариантов. Например, определённые функции проверяют, помимо остальных вещей, что все страницы B-дерева содержат элементы в «логическом» порядке (например, индекс-B-дерево, построенный по столбцу text, должен содержать кортежи, упорядоченные в лексическом порядке с учётом правила сортировки). Если этот конкретный инвариант каким-то образом нарушается, следует ожидать, что бинарный поиск на затронутой странице введёт в заблуждение процедуру сканирования индекса, что приведёт к неверным результатам запросов SQL.

Проверка выполняется теми же процедурами, что используются при сканировании индекса, и это может быть код пользовательского класса операторов. Например, проверка индекса-B-дерева задействует сравнения, выполняемые одной или несколькими опорными функциями B-дерева под номером 1. Подробнее опорные функции класса операторов описываются в Подразделе 37.14.3.

Функции amcheck могут выполнять только суперпользователи.

F.2.1. Функции

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'
-- Не проверять временные таблицы (они могут относиться к другим сеансам):
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)

Этот пример демонстрирует сеанс проверки 10 самых больших индексов системных каталогов в базе данных «test». Так как ошибки не было, все проверенные индексы представляются логически целостными. Естественно, этот запрос можно легко изменить, чтобы функция 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 запрашивается и в основном отношении). Эти блокировки предотвращают одновременное изменение данных командами INSERT, UPDATE и DELETE. Эти блокировки также препятствуют одновременной обработке нижележащего отношения командой VACUUM и другими вспомогательными командами. Заметьте, что эта функция удерживает блокировки только во время выполнения, а не на протяжении всей транзакции.

Дополнительные проверки, проводимые функцией bt_index_parent_check, более ориентированы на выявление различных патологических случаев. В том числе это может быть неправильно реализованный класс операторов B-дерева, используемый проверяемым индексом, или, гипотетически, неизвестные ошибки в нижележащем коде метода доступа индекса-B-дерева. Заметьте, что функцию bt_index_parent_check нельзя применять, когда включён режим горячего резерва (то есть на физических репликах в режиме «только чтение»), в отличие от bt_index_check.

F.2.2. Эффективное использование amcheck

Модуль amcheck может быть полезен для выявления различных типов проблем, которые могут остаться незамеченными при включении контрольных сумм страниц данных. В частности это:

  • Структурные несоответствия, возникающие при некорректной реализации класса операторов.

    В том числе это проблемы, возникающие при изменении правил сравнения в операционной системе. Сравнения данных сортируемого типа, например text, должны быть постоянными (как и все сравнения, применяемые при сканировании индекса-B-дерева), что подразумевает неизменность правил сортировки в операционной системе. Проблемы могут возникать при обновлениях правил в операционной системе, хотя такие случаи редки. Чаще проявляются несоответствия порядка сортировки между ведущим и ведомым сервером, например, из-за различий основных версий используемых операционных систем. Возникающие расхождения обычно наблюдаются только на ведомых серверах, так что и выявить их обычно можно только на них.

    Когда возникает подобная проблема, она может затрагивать не абсолютно все индексы, построенные с порочным правилом сортировки, просто потому что индексированные значения могут иметь тот же абсолютный порядок, независящий от различий поведения. За дополнительными сведениями об использовании в PostgreSQL правил сортировки и локалей операционной системы обратитесь к Разделу 23.1 и Разделу 23.2.

  • Повреждения, вызванные гипотетическими неизвестными ошибками в нижележащем коде методов доступа PostgreSQL или коде сортировки.

    Автоматическая проверка структурной целостности индексов играет важную роль в общем тестировании новых или предлагаемых возможностей PostgreSQL, с которыми может возникнуть логическая несогласованность. И поэтому одна из очевидных стратегий тестирования — регулярно вызывать функции amcheck при проведении стандартных регрессионных тестов. Подробнее о выполнении тестов можно узнать в Разделе 32.1.

  • Ошибки в файловой системе или подсистеме хранения, когда просто не включены контрольные суммы.

    Заметьте, что amcheck рассматривает страницу в том виде, как она представлена в некотором буфере разделяемой памяти к моменту проверки, если при обращению к нужному блоку он уже находится в разделяемом буфере. Вследствие этого, amcheck не обязательно видит данные, находящиеся в файловой системе в момент проверки. Заметьте, что когда контрольные суммы включены, amcheck может выдать ошибку из-за несоответствия контрольных сумм, если в буфер будет считываться испорченный блок.

  • Повреждения, вызванные дефектными чипами ОЗУ или вообще подсистемой памяти.

    PostgreSQL не защищает от ошибок памяти; предполагается, что в эксплуатируемом вами сервере установлена память с ECC (Error Correcting Codes, Коды исправления ошибок) или лучшая защита. Однако память ECC обычно защищает только от ошибок в одном бите и не следует считать её абсолютной защитой от сбоев, приводящих к повреждению памяти.

Вообще говоря, amcheck может доказать только наличие повреждений, но не доказать их отсутствие.

F.2.3. Исправление повреждений

Выдаваемые amcheck ошибки, относящиеся к повреждениям данных, никогда не должны быть ложными. На практике amcheck с большей вероятностью обнаружит программные ошибки, чем проблемы с оборудованием. amcheck выдаёт ошибки в случае условий, которые никогда не должны наблюдаться по определению, так что ошибки amcheck, как правило, требует тщательного анализа.

Общего метода устранения проблем, которые может выявить amcheck, не существует. Начать нужно с поиска корня проблемы, приводящей к нарушению инварианта. Полезную роль в диагностике повреждений, которые выявляет amcheck, может сыграть pageinspect. Одна лишь команда REINDEX может быть неэффективна, когда потребуется исправить повреждения.