Check the logical integrity of the structure of the B-Tree indexes and tables related to the target index relation with amcheck.

Check the logical integrity of the structure of the B-Tree indexes and tables related to the target index relation with amcheck.

WARNING: bt_index_parent_check(..) used here will block INSERT/UPDATE/DELETE! Do not run in the production database.
(used bt_index_parent_check with heapallindexed argument is true) \

When the heapallindexed argument to verification functions is true, an additional phase of verification is performed against the table associated with the target index relation.

The amcheck module provides functions that allow you to verify the logical consistency of the structure of relations. If the structure appears to be valid, no error is raised.
Read more in the documentation.

Requirements

Notes: this extension is already supplied with PostgreSQL packages for version 11 and above. No additional packages are required.

amcheck functions may only be used by superusers.

1. Create extension on the target database

(specify the name of the target database)

psql -d <dbname> -c 'create extension if not exists amcheck'

2. Create SQL script "amcheck.sql"
cat <<EOF > amcheck.sql
----------------------------------------------------------------------------------------
-- Check btree indexes (amcheck)
--
-- WARNING: bt_index_parent_check(..) used here will block INSERT/UPDATE/DELETE!
----------------------------------------------------------------------------------------

set statement_timeout to 0;

do \$\$
declare
  r record;
  sql text;
  ts_pre timestamptz;
begin
  for r in
    select
      row_number() over(order by tc.reltuples) as i,
      count(*) over() as cnt,
      c.oid,
      i.indisunique,
      c.relname,
      c.relpages::int8,
      tc.reltuples::int8 as tuples
    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_class tc on i.indrelid = tc.oid
    join pg_namespace n on c.relnamespace = n.oid
    where
      am.amname = 'btree'
      --and n.nspname = 'public'
      and c.relpersistence <> 't' -- don't check temp tables
      and c.relkind = 'i'
      and i.indisready
      and i.indisvalid
    order by tc.reltuples
  loop
    ts_pre := clock_timestamp();
    raise info '[%] Processing %/%: index: % (index relpages: %; heap tuples: ~%)...',
      ts_pre::timestamptz(3), r.i, r.cnt, r.relname, r.relpages, r.tuples;

    perform bt_index_parent_check(index => r.oid, heapallindexed => true);

    raise info '[%] DONE %/%: index: %. Time taken: %',
      clock_timestamp()::timestamptz(3), r.i, r.cnt, r.relname, (clock_timestamp() - ts_pre);
  end loop;
end \$\$;

EOF

Notes: In this example, commented the condition "and n.nspname = 'public'" to check all available indexes.

3. Check btree indexes

(specify the name of the target database)

psql -d <dbname> -f amcheck.sql 2>&1 | tee -a /tmp/amcheck.$(date "+%F").log

An example of output:

psql:amcheck.sql:49: INFO:  [2021-03-24 21:54:48.853+03] Processing 1/189: index: pg_toast_2600_index (index relpages: 1; heap tuples: ~0)...
psql:amcheck.sql:49: INFO:  [2021-03-24 21:54:48.859+03] DONE 1/189: index: pg_toast_2600_index. Time taken: 00:00:00.005419
psql:amcheck.sql:49: INFO:  [2021-03-24 21:54:48.859+03] Processing 2/189: index: pg_toast_2604_index (index relpages: 1; heap tuples: ~0)...
psql:amcheck.sql:49: INFO:  [2021-03-24 21:54:48.861+03] DONE 2/189: index: pg_toast_2604_index. Time taken: 00:00:00.002093
...
psql:amcheck.sql:49: INFO:  [2021-03-24 21:54:49.677+03] Processing 188/189: index: pg_depend_reference_index (index relpages: 66; heap tuples: ~12313)...
psql:amcheck.sql:49: INFO:  [2021-03-24 21:54:49.766+03] DONE 188/189: index: pg_depend_reference_index. Time taken: 00:00:00.088657
psql:amcheck.sql:49: INFO:  [2021-03-24 21:54:49.766+03] Processing 189/189: index: pg_depend_depender_index (index relpages: 58; heap tuples: ~12313)...
psql:amcheck.sql:49: INFO:  [2021-03-24 21:54:49.822+03] DONE 189/189: index: pg_depend_depender_index. Time taken: 00:00:00.055827
Wait until the checks are completed.

Notes: The exact time of execution depends on the number and size of indexes, as well as from server hardware resources.

If the structure of the index is valid, no error is raised. An example of a invalid index:

ERROR:  item order invariant violated for index "index_name_idx"
DETAIL:  Lower index tid=(2,111) (points to heap tid=(104,6)) higher index tid=(2,112) (points to heap tid=(106,10)) page lsn=8/680B33C8.

If the problem is detected, try re-create the index: REINDEX INDEX CONCURRENTLY <index_name>;

Repairing Corruption

No error concerning corruption raised by amcheck should ever be a false positive. amcheck raises errors in the event of conditions that, by definition, should never happen, and so careful analysis of amcheck errors is often required.

There is no general method of repairing problems that amcheck detects. An explanation for the root cause of an invariant violation should be sought. pageinspect may play a useful role in diagnosing corruption that amcheck detects. A REINDEX may not be effective in repairing corruption.

https://www.postgresql.org/docs/current/amcheck.html

Edited by Vitaliy Kukharik