Перейти к основному содержимому

amcheck — инструменты для проверки согласованности таблиц и индексов

примечание

Эта страница переведена при помощи нейросети GigaChat.

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

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

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

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

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

Функции

bt_index_check(index regclass, heapallindexed boolean, checkunique boolean) returns void

Эти тесты проверяют соблюдение целевым объектом, индексом B-дерева, различных инвариантов. Пример использования:

test=# SELECT bt_index_check(index => c.oid, heapallindexed => i.indisunique),
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 c.relkind = 'i' 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. Запрашивается проверка наличия кортежей кучи в виде кортежей индекса для подмножества уникальных индексов. Поскольку ошибка не возникает, все протестированные индексы кажутся логически согласованными. Естественно, этот запрос можно легко изменить так, чтобы он вызывал bt_index_check для каждого индекса в базе данных, где поддерживается проверка.

bt_index_check получает блокировку AccessShareLock на целевом индексе и таблице-кучах, которой принадлежит данный индекс. Этот режим блокировки аналогичен тому, который используется простыми командами SELECT. Функция bt_index_check не проверяет инварианты, охватывающие отношения родитель-потомок, однако проверит наличие всех кортежей таблицы-кучи в качестве индексных кортежей внутри индекса, когда аргумент heapallindexed установлен в значение true. Когда аргумент checkunique равен значению true, функция bt_index_check проверяет видимость не более одного дублирующего элемента среди записей уникального индекса. При необходимости проведения быстрого теста на целостность в рабочей производственной среде использование bt_index_check часто обеспечивает наилучший компромисс между тщательностью проверки и ограничением влияния на производительность приложения и доступность.

bt_index_parent_check(index regclass, heapallindexed boolean, rootdescend boolean) returns void

bt_index_parent_check проверяет, соответствует ли его цель, индекс B-дерева, различным инвариантам. Опционально, когда аргумент heapallindexed имеет значение true, функция проверяет присутствие всех кортежей таблицы-кучи, которые должны присутствовать в индексе. Когда аргумент checkunique принимает значение true, функция bt_index_parent_check проверяет, что среди повторяющихся элементов уникального индекса видим только один элемент. Если опциональный аргумент rootdescend задан со значением true, проверка повторно находит кортежи на уровне листа, выполняя новый поиск от корневой страницы для каждого кортежа. Набор проверок, которые может выполнить 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 придерживается общего соглашения о том, чтобы генерировать ошибку, если обнаруживает логическое несоответствие или другую проблему.

ShareLock требует блокировки на целевом индексе от bt_index_parent_check (также приобретается блокировка на отношение кучи). Эти блокировки предотвращают одновременное изменение данных командами INSERT, UPDATE и DELETE. Блокировки также предотвращают параллельную обработку базового отношения командой VACUUM, а также всеми другими служебными командами. Обратите внимание, что функция удерживает блокировки только во время выполнения, а не на протяжении всей транзакции.

Дополнительная проверка bt_index_parent_check с большей вероятностью обнаружит различные патологические случаи. Эти случаи могут включать неправильно реализованный класс операторов B-дерева, используемый индексом, который проверяется, или, гипотетически, неизвестные ошибки в основном коде метода доступа к индексу B-дерева. Обратите внимание, что bt_index_parent_check нельзя использовать, когда включен режим горячего резервирования (т.е. на доступных только для чтения физических репликах), в отличие от bt_index_check.

Совет

bt_index_check и bt_index_parent_check выводят сообщения журнала о процессе проверки с уровнями серьезности DEBUG1 и DEBUG2. Эти сообщения предоставляют подробную информацию о процессе проверки, которая может быть интересна разработчикам PostgreSQL. Опытные пользователи также могут найти эту информацию полезной, поскольку она предоставляет дополнительную контекстную информацию в случае обнаружения несоответствия при проверке. Запуск:

SET client_min_messages = DEBUG1;

в интерактивной сессии psql перед запуском запроса проверки отобразит сообщения о ходе проверки с управляемым уровнем детализации.

verify_heapam(relation regclass, on_error_stop boolean, check_toast boolean, skip text, startblock bigint, endblock bigint, blkno OUT bigint, offnum OUT integer, attnum OUT integer, msg OUT text) returns setof record

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

Принимаются следующие необязательные аргументы:

on_error_stop

Если установлено значение true, проверка на наличие повреждений прекращается в конце первого блока, в котором обнаружены какие-либо повреждения.

По умолчанию установлено значение false.

check_toast

Если установлено значение true, поля TOAST проверяются по TOAST-таблице целевого отношения.

Известно, что этот вариант работает медленно. Кроме того, если TOAST-таблица или ее индекс повреждены, проверка их по сравнению с значениями TOAST-полей может привести к сбою сервера, хотя во многих случаях это просто приведет к возникновению ошибки.

По умолчанию установлено значение false.

skip

Если не none, проверка на повреждение пропускает блоки, которые помечены как полностью видимые или полностью замороженные, как указано. Допустимыми вариантами являются all-visible, all-frozen и none.

По умолчанию установлено значение none.

startblock

Если задано, то проверка на повреждение начинается с указанного блока, пропуская все предыдущие блоки. Ошибка заключается в указании startblock вне диапазона блоков в целевой таблице.

По умолчанию проверка начинается с первого блока.

endblock

Если задано, проверка повреждения заканчивается на указанном блоке, пропуская все оставшиеся блоки. Ошибка заключается в указании endblock вне диапазона блоков в целевой таблице.

По умолчанию проверяются все блоки.

Для каждого обнаруженного повреждения verify_heapam возвращает строку со следующими столбцами:

blkno

Номер блока, содержащего поврежденную страницу.

offnum

Номер смещения поврежденного кортежа.

attnum

Номер атрибута поврежденного столбца в кортеже, если повреждение относится к конкретному столбцу, а не ко всему кортежу.

msg

Сообщение, описывающее обнаруженную проблему.

Необязательная проверка heapallindexed

Когда аргумент heapallindexed в функциях проверки B-деревьев имеет значение true, выполняется дополнительная фаза верификации, связанная с таблицей, на которую ссылается целевой индекс. Эта фаза включает «фиктивную» операцию CREATE INDEX, которая проверяет наличие всех гипотетических новых записей индекса с помощью временной структуры, обобщающей данные в памяти (эта структура строится по мере необходимости во время основной первой фазы проверки). Структура создает «отпечаток» каждого кортежа, найденного в целевом индексе. Основной принцип проверки heapallindexed заключается в том, что новый индекс, эквивалентный существующему целевому индексу, должен содержать только те записи, которые можно найти в текущей структуре.

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

Размер обобщающей структуры ограничен параметром maintenance_work_mem. Чтобы гарантировать вероятность не более 2% пропуска несоответствия для каждого кортежа в таблице, который должен быть представлен в индексе, требуется примерно 2 байта памяти на кортеж. При уменьшении доступной памяти на кортеж вероятность пропуска ошибки постепенно возрастает. Такой подход существенно ограничивает нагрузку при проверке, лишь незначительно снижая вероятность обнаружения проблем, особенно в системах, где верификация выполняется как часть регулярного обслуживания. Каждая отсутствующая или некорректная запись имеет новый шанс быть обнаруженной при последующих проверках.

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

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

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

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

    Если возникает такая проблема, она может не повлиять на каждый отдельный индекс, который упорядочен с использованием затронутого сопоставления, просто потому, что проиндексированные значения могут случайно иметь одинаковый абсолютный порядок независимо от поведенческой непоследовательности. См. разделы «Поддержка языковых стандартов» и «Поддержка правил сортировки» для получения дополнительной информации о том, как PostgreSQL использует системные локализации и сопоставление.

  • Структурные несоответствия между индексами и отношениями в куче, которые индексируются (когда выполняется проверка heapallindexed).

    Нет перекрестной проверки индексов по отношениям в куче во время нормальной работы. Симптомы повреждения кучи могут быть незаметными.

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

    Автоматическая проверка структурной целостности индексов играет роль в общем тестировании новых или предлагаемых функций PostgreSQL, которые могли бы логически допустить введение непоследовательности. Проверка структуры таблицы и связанной с ней информации о видимости и состоянии транзакции играет аналогичную роль. Одна очевидная стратегия тестирования заключается в непрерывном вызове функций при запуске стандартных регрессионных тестов. См. раздел 33.1 для получения подробной информации о запуске тестов.

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

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

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

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

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

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

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

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

Поврежденные отношения вызывают наибольшую озабоченность в реальных производственных средах, именно в тех средах, где нежелательны мероприятия с высоким уровнем риска. По этой причине verify_heapam был разработан для диагностики повреждений без чрезмерного риска. Он не может защитить от всех причин сбоев бэкенда, поскольку даже выполнение вызывающего запроса может быть небезопасным в сильно поврежденной системе. Осуществляется доступ к таблицам каталога catalog tables и он может быть проблематичным, если сами каталоги повреждены.

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

Устранение повреждений

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

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