Использование amcheck
Обзор
Расширение amcheck содержит функции, позволяющие проверять логическую целостность структуры отношений. Оно полезно для выявления различных типов проблем, которые могут остаться незамеченными даже при включении data checksums. К ним относятся:
-
Структурные несоответствия, возникающие при некорректной реализации класса операторов.
-
Структурные несоответствия между индексами и индексируемыми отношениями в heap.
-
Повреждение данных, вызванное гипотетическими необнаруженными багами в базовом коде методов доступа, коде сортировки или коде управления транзакциями PostgreSQL.
-
Сбои в файловой системе или подсистеме хранения данных, когда контрольные суммы не включены.
-
Повреждение данных, вызванное неисправной оперативной памятью или вообще подсистемой памяти.
Страницы отношений, которые имеют правильный формат, внутренне согласованы и корректны относительно своих собственных контрольных сумм, все еще могут содержать логические ошибки. Этот тип ошибок невозможно обнаружить с помощью контрольных сумм. В качестве примера можно привести значения в основной таблице, для которых отсутствует соответствующая запись в таблице TOAST, и кортежи в основной таблице с идентификатором транзакции, который старше самого старого действительного идентификатора транзакции в базе данных или кластере.
|
ПРИМЕЧАНИЕ
|
Функции проверки B-дерева расширения amcheck исследуют различные инварианты в структуре отношения. Корректность функций методов доступа, лежащих в основе сканирования индексов и других операций, зависит от постоянного соблюдения инвариантов. Функции проверяют, что все страницы B-дерева содержат элементы в "логическом" порядке (например, индекс B-дерева по столбцу типа text должен содержать кортежи, упорядоченные в лексическом порядке с учетом правила сортировки). Если этот инвариант по какой-либо причине не выполняется, можно ожидать, что бинарный поиск на соответствующей странице будет некорректно выполнять сканирование индексов, что приведет к неправильным результатам SQL-запросов.
В отличие от функций проверки B-деревьев, которые сообщают о повреждении, генерируя ошибки, функция проверки heap verify_heapam анализирует таблицу и пытается вернуть набор строк: по одной строке на каждое обнаруженное повреждение. Однако, если ресурсы, используемые функцией verify_heapam, также повреждены, функция может оказаться не в состоянии продолжить работу и выдаст ошибку.
Если amcheck обнаруживает повреждение данных, ложные срабатывания практически исключаются. Расширение amcheck рассматривает ситуации, которые никогда не должны возникнуть, как ошибки, поэтому ошибки amcheck обычно требуют тщательного анализа.
Не существует общего метода решения проблем, обнаруживаемых amcheck. Можно начать с поиска первопричины нарушения инварианта. Расширение pageinspect может быть полезно для диагностики повреждений, найденных amcheck.
Установка
Пакет, требуемый для установки amcheck, поставляется с ADP. Чтобы использовать amcheck, необходимо только выполнить команду CREATE EXTENSION в той базе данных, в которую вы хотите установить расширение:
CREATE EXTENSION amcheck;
|
ПРИМЕЧАНИЕ
Если расширение amcheck создано в базе данных template1, используемой в качестве темплейта по умолчанию, во всех вновь создаваемых базах данных будет установлено это расширение.
|
ADP использует версию
1.3
расширения amcheck. Чтобы это проверить, можно выполнить следующий запрос:
SELECT extversion FROM pg_extension
WHERE extname = 'amcheck';
extversion ------------ 1.3
После создания расширения amcheck его функции становятся доступны в текущей базе данных.
Функции
Как упоминалось выше, расширение amcheck предоставляет функции для проверки логической целостности структуры отношений, в частности индексов B-дерева.
Права доступа к функциям amcheck можно предоставлять и не суперпользователям, однако перед этим следует тщательно изучить вопросы безопасности и конфиденциальности данных. Хотя функции amcheck в первую очередь предоставляют информацию о структуре данных и характере обнаруженных повреждений, а не отображают сами поврежденные данные, если злоумышленник сможет выполнить эти функции, и особенно если ему удастся повредить данные, он может получить конфиденциальную информацию из данных, отображаемых этими функциями.
bt_index_check
Функция bt_index_check проверяет, соблюдаются ли в целевом индексе B-дерева различные инварианты.
bt_index_check(<index> regclass, <heapallindexed> boolean) returns void
где:
-
<index>— целевой индекс B-дерева. -
<heapallindexed>(необязательный параметр) — если равенtrue, для таблицы, связанной с отношением целевого индекса, добавляется дополнительный этап проверки. Он включает в себя "фиктивную" операциюCREATE INDEX, которая проверяет наличие всех гипотетических новых кортежей индекса во временной, хранящейся в памяти суммирующей структуре (она создается по мере необходимости на первом этапе проверки). Суммирующая структура "отпечатывает" каждый кортеж, найденный в целевом индексе. Основная идея этой проверки заключается в том, что новый индекс, эквивалентный существующему целевому индексу, должен содержать только те записи, которые можно найти в существующей структуре. Значение по умолчанию —false.
Функция bt_index_check получает блокировку типа AccessShareLock на целевой индекс и отношение в heap, которому он принадлежит. Этот режим блокировки совпадает с режимом блокировки, используемым операторами SELECT, поэтому bt_index_check можно использовать в производственном окружении.
Функция bt_index_check не проверяет инварианты, охватывающие отношения "родитель/потомок", а проверяет наличие всех кортежей heap в качестве кортежей индекса, когда heapallindexed имеет значение true.
Когда в производственном окружении требуется стандартная, несложная проверка на наличие повреждений, bt_index_check представляет собой разумный компромисс между полнотой проверки и минимизацией влияния на производительность и доступность приложения.
Функция bt_index_check выводит сообщения о процессе проверки на уровнях важности лог-сообщений debug1 и debug2. Эти сообщения содержат подробную информацию о процессе проверки. Чтобы изменить уровень важности лог-сообщений для текущей сессии, используйте следующую команду в интерактивной сессии psql:
SET client_min_messages = DEBUG1;
За дополнительной информацией о настройке параметров логирования обратитесь к статье Логирование.
Для того чтобы протестировать функцию bt_index_check, создайте таблицу и заполните ее данными:
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INTEGER NOT NULL,
date DATE NOT NULL,
amount DECIMAL(10,2),
status VARCHAR(20)
);
INSERT INTO orders (customer_id, date, amount, status)
SELECT
(random() * 500)::integer,
CURRENT_DATE - (random() * 365)::integer,
(random() * 500)::decimal,
CASE WHEN random() < 0.4 THEN 'pending'
WHEN random() < 0.7 THEN 'shipped'
ELSE 'delivered' END
FROM generate_series(1, 2000);
Создайте индексы:
CREATE INDEX idx_orders_customer ON orders(customer_id);
CREATE INDEX idx_orders_composite ON orders(customer_id, date);
Вызовите функцию bt_index_check:
SELECT bt_index_check('idx_orders_customer');
Результат:
DEBUG: verifying consistency of tree structure for index "idx_orders_customer" DEBUG: verifying level 1 (true root level) DEBUG: verifying level 0 (leaf level) bt_index_check ---------------- (1 row)
Запустите функцию bt_index_check, установив значение true параметру heapallindexed:
SELECT bt_index_check('idx_orders_composite', true);
Результат:
DEBUG: verifying consistency of tree structure for index "idx_orders_composite" DEBUG: verifying level 1 (true root level) DEBUG: verifying level 0 (leaf level) DEBUG: verifying that tuples from index "idx_orders_composite" are present in "orders" DEBUG: finished verifying presence of 2000 tuples from table "orders" with bitset 0.24% set bt_index_check ---------------- (1 row)
bt_index_parent_check
Функция bt_index_parent_check также проверяет, соблюдаются ли в целевом индексе B-дерева различные инварианты. В дополнение к инвариантам, тестируемым bt_index_check, bt_index_parent_check проверяет инварианты, охватывающие отношения "родитель/потомок", включая отсутствующие нисходящие ссылки в структуре индекса.
bt_index_parent_check(<index> regclass, <heapallindexed> boolean, <rootdescend> boolean) returns void
где:
-
<index>— целевой индекс B-дерева. -
<heapallindexed>(необязательный параметр) — если равенtrue, для таблицы, связанной с отношением целевого индекса, добавляется дополнительный этап проверки. Он включает в себя "фиктивную" операциюCREATE INDEX, которая проверяет наличие всех гипотетических новых кортежей индекса во временной, хранящейся в памяти суммирующей структуре (она создается по мере необходимости на первом этапе проверки). Суммирующая структура "отпечатывает" каждый кортеж, найденный в целевом индексе. Основная идея этой проверки заключается в том, что новый индекс, эквивалентный существующему целевому индексу, должен содержать только те записи, которые можно найти в существующей структуре. Значение по умолчанию —false. -
<rootdescend>(необязательный параметр) — если равенtrue, при проверке для каждого кортежа на уровне листьев производится еще один поиск, начиная с корневой страницы.
Функция bt_index_parent_check получает блокировку типа ShareLock на целевой индекс и отношение в heap, которому он принадлежит. Эта блокировка предотвращает одновременное изменение данных командами INSERT, UPDATE и DELETE. Она также делает невозможной одновременную обработку базового отношения операцией вакуумирования и всеми другими вспомогательными командами. Обратите внимание, что bt_index_parent_check удерживает блокировки только во время выполнения, а не на протяжении всей транзакции.
Функция bt_index_parent_check, так же как и bt_index_check, выводит сообщения о процессе проверки на уровнях важности лог-сообщений debug1 и debug2.
В качестве примера вызовите функцию bt_index_parent_check для индекса idx_orders_composite, созданного выше:
SELECT bt_index_parent_check('idx_orders_composite', true, true);
Результат:
DEBUG: verifying consistency of tree structure for index "idx_orders_composite" with cross-level checks DEBUG: verifying level 1 (true root level) DEBUG: verifying level 0 (leaf level) DEBUG: verifying that tuples from index "idx_orders_composite" are present in "orders" DEBUG: finished verifying presence of 2000 tuples from table "orders" with bitset 0.24% set bt_index_parent_check ----------------------- (1 row)
verify_heapam
Функция verify_heapam проверяет таблицу, последовательность или материализованное представление на наличие структурных повреждений, когда страницы отношения содержат данные с некорректным форматированием, и на наличие логических повреждений, когда структура страниц не повреждена, но не соответствует остальной части кластера.
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
Список параметров функции verify_heapam перечислен в таблице ниже. Все параметры, кроме <relation>, являются необязательными.
| Название | Описание | Значение по умолчанию |
|---|---|---|
relation |
Целевое отношение |
— |
on_error_stop |
Если значение равно |
false |
check_toast |
Если значение равно |
false |
skip |
Допустимые значения: |
none |
startblock |
Если указано значение, проверка на повреждение начинается с указанного блока, пропуская все предыдущие блоки. Указание начального блока вне диапазона блоков в целевой таблице приведет к ошибке |
Проверка начинается с первого блока |
endblock |
Если указано значение, проверка на наличие повреждений завершается на указанном блоке, пропуская все оставшиеся блоки. Указание конечного блока вне диапазона блоков в целевой таблице приведет к ошибке |
Все блоки проверяются |
Для каждого обнаруженного повреждения функция verify_heapam возвращает строку со столбцами, перечисленными в таблице ниже.
| Название | Описание |
|---|---|
blkno |
Номер блока, содержащего поврежденную страницу |
offnum |
Номер смещения поврежденного кортежа |
attnum |
Номер атрибута поврежденного столбца в кортеже, если поврежден столбец, а не весь кортеж |
msg |
Сообщение с описанием проблемы |
Пример:
SELECT * FROM verify_heapam(
relation => 'orders'::regclass,
on_error_stop => false,
check_toast => true
);
Результат:
blkno | offnum | attnum | msg -------+--------+--------+----- (0 rows)