pageinspect

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

Функции общего назначения

get_raw_page(relname text, fork text, blkno bigint) returns bytea

Функция get_raw_page читает заданный блок именованного отношения и возвращает его копию в виде значения bytea. Это позволяет получить одну согласованную во времени копию блока. В параметре fork нужно передать 'main', чтобы обратиться к основной ветви данных, 'fsm' — к карте свободного пространства, 'vm' — к карте видимости, или 'init' — к ветви инициализации.

get_raw_page(relname text, blkno bigint) returns bytea

Упрощенная версия функции get_raw_page для чтения данных из основной ветви. Равнозначна get_raw_page(relname, 'main', blkno)

page_header(page bytea) returns record

Функция page_header показывает поля, общие для всех страниц кучи и индекса QHB.

В качестве аргумента ей следует передавать образ страницы, полученный с помощью get_raw_page. Например:

test=# SELECT * FROM page_header(get_raw_page('pg_class', 0));
    lsn    | checksum | flags  | lower | upper | special | pagesize | version | prune_xid
-----------+----------+--------+-------+-------+---------+----------+---------+-----------
 0/24A1B50 |        0 |      1 |   232 |   368 |    8192 |     8192 |       4 |         0

Возвращаемые столбцы соответствуют полям в структуре PageHeaderData. Подробную информацию см. в src/include/storage/bufpage.h.

Поле checksum содержит контрольную сумму, сохраненную в странице. Эта сумма может быть неверной, если страница каким-то образом повреждена. Если в данном экземпляре СУБД контрольные суммы выключены, сохраненное значение не имеет смысла.

page_checksum(page bytea, blkno bigint) returns smallint

Функция page_checksum вычисляет контрольную сумму для страницы так, будто эта страница находилась в заданном блоке.

В качестве аргумента ей следует передавать образ страницы, полученный с помощью get_raw_page. Например:

test=# SELECT page_checksum(get_raw_page('pg_class', 0), 0);
 page_checksum
---------------
         13443

Обратите внимание, что вычисление контрольной суммы зависит от номера блока, поэтому обеим функциям следует передавать одинаковые номера блоков (за исключением случаев эзотерической отладки).

Контрольные суммы, вычисленные этой функцией, можно сравнить с результирующим полем checksum функции page_header. Если в данном экземпляре СУБД контрольные суммы включены, эти значения должны быть равны.

fsm_page_contents(page bytea) returns text

Функция fsm_page_contents показывает внутреннюю структуру узла на странице FSM. Например:

test=# SELECT fsm_page_contents(get_raw_page('pg_class', 'fsm', 0));

Вывод состоит из нескольких текстовых строк, по одной строке для каждого узла двоичного дерева на заданной странице. Выводятся только ненулевые узлы. Также выводится так называемый указатель «вперед», которые указывает на следующий слот, возвращаемый с этой страницы.

Более подробную информацию о структуре страницы FSM см. в src/backend/storage/freespace/README.

Функции для исследования кучи

heap_page_items(page bytea) returns setof record

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

В качестве аргумента ей следует передавать образ страницы кучи, полученный с помощью get_raw_page. Например:

test=# SELECT * FROM heap_page_items(get_raw_page('pg_class', 0));

Описание возвращаемых полей см. в src/include/storage/itemid.h и src/include/access/htup_details.h.

Распаковать биты флагов t_infomask and t_infomask2 для кортежей кучи можно с помощью функции heap_tuple_infomask_flags.

tuple_data_split(rel_oid oid, t_data bytea, t_infomask integer, t_infomask2 integer, t_bits text [, do_detoast bool]) returns bytea[]

Функция tuple_data_split разделяет данные кортежа на атрибуты так же, как это происходит внутри сервера.

test=# SELECT tuple_data_split('pg_class'::regclass, t_data, t_infomask, t_infomask2, t_bits) FROM heap_page_items(get_raw_page('pg_class', 0));

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

Если параметр do_detoast равен true, атрибуты будут распаковываться по мере необходимости. Значение по умолчанию — false.

heap_page_item_attrs(page bytea, rel_oid regclass [, do_detoast bool]) returns setof record

Функция heap_page_item_attrs равнозначна функции heap_page_items, за исключением того, что она возвращает исходные данные кортежа в виде массива атрибутов, которые при необходимости могут быть распакованы, если установлен флаг do_detoast (по умолчанию false, т. е. они не распаковываются).

В качестве аргумента ей следует передавать образ страницы кучи, полученный с помощью get_raw_page. Например:

test=# SELECT * FROM heap_page_item_attrs(get_raw_page('pg_class', 0), 'pg_class'::regclass);

heap_tuple_infomask_flags(t_infomask integer, t_infomask2 integer) returns record

Функция heap_tuple_infomask_flags декодирует значения t_infomask и t_infomask2, возвращаемые функцией heap_page_items, в множество удобочитаемых массивов с именами флагов, где в одном столбце перечислены все флаги по отдельности, а в другом — комбинированные флаги. Например:

test=# SELECT t_ctid, raw_flags, combined_flags
         FROM heap_page_items(get_raw_page('pg_class', 0)),
           LATERAL heap_tuple_infomask_flags(t_infomask, t_infomask2)
         WHERE t_infomask IS NOT NULL OR t_infomask2 IS NOT NULL;

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

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

Описания возвращаемых имен флагов см. в src/include/access/htup_details.h.

Функции для индексов B-деревьев

bt_metap(relname text) returns record

Функция bt_metap возвращает информацию о метастранице индекса B-дерева. Например:

test=# SELECT * FROM bt_metap('pg_cast_oid_index');
-[ RECORD 1 ]-------------+-------
magic                     | 340322
version                   | 4
root                      | 1
level                     | 0
fastroot                  | 1
fastlevel                 | 0
last_cleanup_num_delpages | 0
last_cleanup_num_tuples   | 230
allequalimage             | f

bt_page_stats(relname text, blkno bigint) returns record

Функция bt_page_stats возвращает сводную информацию по единичным страницам индексов B-деревьев. Например:

test=# SELECT * FROM bt_page_stats('pg_cast_oid_index', 1);
-[ RECORD 1 ]-+-----
blkno         | 1
type          | l
live_items    | 224
dead_items    | 0
avg_item_size | 16
page_size     | 8192
free_size     | 3668
btpo_prev     | 0
btpo_next     | 0
btpo_level    | 0
btpo_flags    | 3

bt_page_items(relname text, blkno bigint) returns setof record

Функция bt_page_items возвращает подробную информацию обо всех элементах на странице индекса B-дерева. Например:

test=# SELECT itemoffset, ctid, itemlen, nulls, vars, data, dead, htid, tids[0:2] AS some_tids
        FROM bt_page_items('tenk2_hundred', 5);
 itemoffset |   ctid    | itemlen | nulls | vars |          data           | dead |  htid  |      some_tids
------------+-----------+---------+-------+------+-------------------------+------+--------+---------------------
          1 | (16,1)    |      16 | f     | f    | 30 00 00 00 00 00 00 00 |      |        |
          2 | (16,8292) |     616 | f     | f    | 24 00 00 00 00 00 00 00 | f    | (1,6)  | {"(1,6)","(10,22)"}
          3 | (16,8292) |     616 | f     | f    | 25 00 00 00 00 00 00 00 | f    | (1,18) | {"(1,18)","(4,22)"}
          4 | (16,8292) |     616 | f     | f    | 26 00 00 00 00 00 00 00 | f    | (4,18) | {"(4,18)","(6,17)"}
          5 | (16,8292) |     616 | f     | f    | 27 00 00 00 00 00 00 00 | f    | (1,2)  | {"(1,2)","(1,19)"}
          6 | (16,8292) |     616 | f     | f    | 28 00 00 00 00 00 00 00 | f    | (2,24) | {"(2,24)","(4,11)"}
          7 | (16,8292) |     616 | f     | f    | 29 00 00 00 00 00 00 00 | f    | (2,17) | {"(2,17)","(11,2)"}
          8 | (16,8292) |     616 | f     | f    | 2a 00 00 00 00 00 00 00 | f    | (0,25) | {"(0,25)","(3,20)"}
          9 | (16,8292) |     616 | f     | f    | 2b 00 00 00 00 00 00 00 | f    | (0,10) | {"(0,10)","(0,14)"}
         10 | (16,8292) |     616 | f     | f    | 2c 00 00 00 00 00 00 00 | f    | (1,3)  | {"(1,3)","(3,9)"}
         11 | (16,8292) |     616 | f     | f    | 2d 00 00 00 00 00 00 00 | f    | (6,28) | {"(6,28)","(11,1)"}
         12 | (16,8292) |     616 | f     | f    | 2e 00 00 00 00 00 00 00 | f    | (0,27) | {"(0,27)","(1,13)"}
         13 | (16,8292) |     616 | f     | f    | 2f 00 00 00 00 00 00 00 | f    | (4,17) | {"(4,17)","(4,21)"}
(13 rows)

Это листовая страница B-дерева. Все кортежи, указывающие на таблицу, оказались кортежами со списками идентификаторов (в каждом из которых хранится в сумме 100 шестибайтных TID (идентификаторов кортежей)). Кроме того, по смещению itemoffset 1 находится кортеж «верхний ключ». В данном примере ctid используется для хранения закодированной информации о каждом кортеже, хотя на листовой странице кортежи часто содержат в поле ctid непосредственно TID кучи. Поле tids содержит список TID в виде списка идентификаторов.

На внутренней странице (здесь не показана) часть номера блока в ctid является «ссылкой вниз», то есть номером блока другой страницы в самом индексе. Часть смещения (второе число) ctid содержит закодированную информацию о кортеже, в частности, количество столбцов в нем (при отсечении суффикса могут быть удалены ненужные заключительные столбцы). Отсекаемые столбцы воспринимаются как содержащие значение «минус бесконечность».

В поле htid показывается TID кортежа в куче, независимо от его нижележащего представления. Это значение может совпадать со ctid или может быть декодировано из альтернативных представлений, используемых в кортежах со списками идентификаторов и кортежами со внутренних страниц. В кортежах на внутренних страницах столбец с TID кучи на уровне реализации обычно отсекается, что выглядит как значение NULL в столбце htid.

Обратите внимание, что первый элемент в любой, кроме самой правой, странице (т. е. в любой странице с ненулевым значением в поле btpo_next) является «верхним ключом», то есть его поле data служит верхней границей для всех элементов, находящихся на этой странице, а поле ctid не указывает на другой блок. Кроме того, на внутренних страницах в первом действительном элементе с данными (в первом элементе после верхнего ключа) обязательно будут усечены все столбцы, не оставив в поле data фактического значения. Однако такой элемент содержит в своем поле ctid корректную ссылку вниз.

Дополнительную информацию о структуре индексов B-деревьев см. в подразделе Структура В-дерева. Дополнительную информацию об исключении дубликатов и списках идентификаторов см. в подразделе Дедупликация.

bt_page_items(page bytea) returns setof record

Функции bt_page_items также можно передать страницу в виде значения bytea. Вызывая эту функцию, ей следует передавать в аргументе образ страницы, полученный с помощью функции get_raw_page. Так, последний пример можно переписать следующим образом:

test=# SELECT itemoffset, ctid, itemlen, nulls, vars, data, dead, htid, tids[0:2] AS some_tids
        FROM bt_page_items(get_raw_page('tenk2_hundred', 5));
 itemoffset |   ctid    | itemlen | nulls | vars |          data           | dead |  htid  |      some_tids
------------+-----------+---------+-------+------+-------------------------+------+--------+---------------------
          1 | (16,1)    |      16 | f     | f    | 30 00 00 00 00 00 00 00 |      |        |
          2 | (16,8292) |     616 | f     | f    | 24 00 00 00 00 00 00 00 | f    | (1,6)  | {"(1,6)","(10,22)"}
          3 | (16,8292) |     616 | f     | f    | 25 00 00 00 00 00 00 00 | f    | (1,18) | {"(1,18)","(4,22)"}
          4 | (16,8292) |     616 | f     | f    | 26 00 00 00 00 00 00 00 | f    | (4,18) | {"(4,18)","(6,17)"}
          5 | (16,8292) |     616 | f     | f    | 27 00 00 00 00 00 00 00 | f    | (1,2)  | {"(1,2)","(1,19)"}
          6 | (16,8292) |     616 | f     | f    | 28 00 00 00 00 00 00 00 | f    | (2,24) | {"(2,24)","(4,11)"}
          7 | (16,8292) |     616 | f     | f    | 29 00 00 00 00 00 00 00 | f    | (2,17) | {"(2,17)","(11,2)"}
          8 | (16,8292) |     616 | f     | f    | 2a 00 00 00 00 00 00 00 | f    | (0,25) | {"(0,25)","(3,20)"}
          9 | (16,8292) |     616 | f     | f    | 2b 00 00 00 00 00 00 00 | f    | (0,10) | {"(0,10)","(0,14)"}
         10 | (16,8292) |     616 | f     | f    | 2c 00 00 00 00 00 00 00 | f    | (1,3)  | {"(1,3)","(3,9)"}
         11 | (16,8292) |     616 | f     | f    | 2d 00 00 00 00 00 00 00 | f    | (6,28) | {"(6,28)","(11,1)"}
         12 | (16,8292) |     616 | f     | f    | 2e 00 00 00 00 00 00 00 | f    | (0,27) | {"(0,27)","(1,13)"}
         13 | (16,8292) |     616 | f     | f    | 2f 00 00 00 00 00 00 00 | f    | (4,17) | {"(4,17)","(4,21)"}
(13 rows)

В остальном данная функция работает так, как описано выше.

Функции для индексов BRIN

brin_page_type(page bytea) returns text

Функция brin_page_type возвращает тип страницы для заданной страницы индекса BRIN или выдает ошибку, если эта страница не является корректной страницей BRIN. Например:

test=# SELECT brin_page_type(get_raw_page('brinidx', 0));
 brin_page_type
----------------
 meta

brin_metapage_info(page bytea) returns record

Функция brin_metapage_info возвращает разнообразную информацию о метастранице индекса BRIN. Например:

test=# SELECT * FROM brin_metapage_info(get_raw_page('brinidx', 0));
   magic    | version | pagesperrange | lastrevmappage
------------+---------+---------------+----------------
 0xA8109CFA |       1 |             4 |              2

brin_revmap_data(page bytea) returns setof tid

Функция brin_revmap_data возвращает список идентификаторов кортежей со страницы сопоставлений диапазонов индекса BRIN. Например:

test=# SELECT * FROM brin_revmap_data(get_raw_page('brinidx', 2)) LIMIT 5;
  pages
---------
 (6,137)
 (6,138)
 (6,139)
 (6,140)
 (6,141)

brin_page_items(page bytea, index oid) returns setof record

Функция brin_page_items возвращает данные, хранящиеся на странице данных BRIN. Например:

test=# SELECT * FROM brin_page_items(get_raw_page('brinidx', 5),
                                     'brinidx')
       ORDER BY blknum, attnum LIMIT 6;
 itemoffset | blknum | attnum | allnulls | hasnulls | placeholder |    value
------------+--------+--------+----------+----------+-------------+--------------
        137 |      0 |      1 | t        | f        | f           |
        137 |      0 |      2 | f        | f        | f           | {1 .. 88}
        138 |      4 |      1 | t        | f        | f           |
        138 |      4 |      2 | f        | f        | f           | {89 .. 176}
        139 |      8 |      1 | t        | f        | f           |
        139 |      8 |      2 | f        | f        | f           | {177 .. 264}

Возвращаемые столбцы соответствуют полям в структурах BrinMemTuple и BrinValues. Подробную информацию см. в src/include/access/brin_tuple.h.

Функции для индексов GIN

gin_metapage_info(page bytea) returns record

Функция gin_metapage_info возвращает информацию о метастранице индекса GIN. Например:

test=# SELECT * FROM gin_metapage_info(get_raw_page('gin_index', 0));
-[ RECORD 1 ]----+-----------
pending_head     | 4294967295
pending_tail     | 4294967295
tail_free_size   | 0
n_pending_pages  | 0
n_pending_tuples | 0
n_total_pages    | 7
n_entry_pages    | 6
n_data_pages     | 0
n_entries        | 693
version          | 2

gin_page_opaque_info(page bytea) returns record

Функция gin_page_opaque_info возвращает информацию о непрозрачной области индекса GIN, например, тип страницы. Например:

test=# SELECT * FROM gin_page_opaque_info(get_raw_page('gin_index', 2));
 rightlink | maxoff |         flags
-----------+--------+------------------------
         5 |      0 | {data,leaf,compressed}
(1 row)

gin_leafpage_items(page bytea) returns setof record

Функция gin_leafpage_items возвращает информацию о данных, хранящихся на листовой странице GIN. Например:

test=# SELECT first_tid, nbytes, tids[0:5] AS some_tids
        FROM gin_leafpage_items(get_raw_page('gin_test_idx', 2));
 first_tid | nbytes |                        some_tids
-----------+--------+----------------------------------------------------------
 (8,41)    |    244 | {"(8,41)","(8,43)","(8,44)","(8,45)","(8,46)"}
 (10,45)   |    248 | {"(10,45)","(10,46)","(10,47)","(10,48)","(10,49)"}
 (12,52)   |    248 | {"(12,52)","(12,53)","(12,54)","(12,55)","(12,56)"}
 (14,59)   |    320 | {"(14,59)","(14,60)","(14,61)","(14,62)","(14,63)"}
 (167,16)  |    376 | {"(167,16)","(167,17)","(167,18)","(167,19)","(167,20)"}
 (170,30)  |    376 | {"(170,30)","(170,31)","(170,32)","(170,33)","(170,34)"}
 (173,44)  |    197 | {"(173,44)","(173,45)","(173,46)","(173,47)","(173,48)"}
(7 rows)

Функции для индексов GiST

gist_page_opaque_info(page bytea) returns record

Функция gist_page_opaque_info возвращает информацию из непрозрачной области страницы индекса GiST, например, значения NSN, rightlink и тип страницы. Например:

test=# SELECT * FROM gist_page_opaque_info(get_raw_page('test_gist_idx', 2));
 lsn | nsn | rightlink | flags
-----+-----+-----------+--------
 0/1 | 0/0 |         1 | {leaf}
(1 row)

gist_page_items(page bytea, index_oid regclass) returns setof record

Функция gist_page_items возвращает информацию о данных, хранящихся на странице индекса GiST. Например:

test=# SELECT * FROM gist_page_items(get_raw_page('test_gist_idx', 0), 'test_gist_idx');
 itemoffset |   ctid    | itemlen | dead |       keys
------------+-----------+---------+------+-------------------
          1 | (1,65535) |      40 | f    | (p)=((166,166))
          2 | (2,65535) |      40 | f    | (p)=((332,332))
          3 | (3,65535) |      40 | f    | (p)=((498,498))
          4 | (4,65535) |      40 | f    | (p)=((664,664))
          5 | (5,65535) |      40 | f    | (p)=((830,830))
          6 | (6,65535) |      40 | f    | (p)=((996,996))
          7 | (7,65535) |      40 | f    | (p)=((1000,1000))
(7 rows)

gist_page_items_bytea(page bytea) returns setof record

Функция схожа с gist_page_items, но возвращает данные ключа в виде исходного двоичного объекта bytea. Так как она не пытается декодировать ключ, ей не требуется знать, какой индекс задействован. Например:

test=# SELECT * FROM gist_page_items_bytea(get_raw_page('test_gist_idx', 0));
 itemoffset |   ctid    | itemlen | dead |                                      key_data
------------+-----------+---------+------+-----------------------------------------​-------------------------------------------
          1 | (1,65535) |      40 | f    | \x00000100ffff28000000000000c0644000000000​00c06440000000000000f03f000000000000f03f
          2 | (2,65535) |      40 | f    | \x00000200ffff28000000000000c0744000000000​00c074400000000000e064400000000000e06440
          3 | (3,65535) |      40 | f    | \x00000300ffff28000000000000207f4000000000​00207f400000000000d074400000000000d07440
          4 | (4,65535) |      40 | f    | \x00000400ffff28000000000000c0844000000000​00c084400000000000307f400000000000307f40
          5 | (5,65535) |      40 | f    | \x00000500ffff28000000000000f0894000000000​00f089400000000000c884400000000000c88440
          6 | (6,65535) |      40 | f    | \x00000600ffff28000000000000208f4000000000​00208f400000000000f889400000000000f88940
          7 | (7,65535) |      40 | f    | \x00000700ffff28000000000000408f4000000000​00408f400000000000288f400000000000288f40
(7 rows)

Функции для хэш-индексов

hash_page_type(page bytea) returns text

Функция hash_page_type возвращает тип страницы для заданной страницы хэш-индекса. Например:

test=# SELECT hash_page_type(get_raw_page('con_hash_index', 0));
 hash_page_type
----------------
 metapage

hash_page_stats(page bytea) returns setof record

Функция hash_page_stats возвращает информацию о странице ячейки или переполнения хэш-индекса. Например:

test=# SELECT * FROM hash_page_stats(get_raw_page('con_hash_index', 1));
-[ RECORD 1 ]---+-----------
live_items      | 407
dead_items      | 0
page_size       | 8192
free_size       | 8
hasho_prevblkno | 4096
hasho_nextblkno | 8474
hasho_bucket    | 0
hasho_flag      | 66
hasho_page_id   | 65408

hash_page_items(page bytea) returns setof record

Функция hash_page_items возвращает информацию о данных, хранящихся на странице ячейки или переполнения хэш-индекса. Например:

test=# SELECT * FROM hash_page_items(get_raw_page('con_hash_index', 1)) LIMIT 5;
 itemoffset |   ctid    |    data
------------+-----------+------------
          1 | (899,77)  | 1053474816
          2 | (897,29)  | 1053474816
          3 | (894,207) | 1053474816
          4 | (892,159) | 1053474816
          5 | (890,111) | 1053474816

hash_bitmap_info(index oid, blkno bigint) returns record

Функция hash_bitmap_info показывает состояние бита в странице битовой карты для определенной страницы переполнения хэш-индекса. Например:

test=# SELECT * FROM hash_bitmap_info('con_hash_index', 2052);
 bitmapblkno | bitmapbit | bitstatus
-------------+-----------+-----------
          65 |         3 | t

hash_metapage_info(page bytea) returns record

Функция hash_metapage_info возвращает информацию, хранящуюся в метастранице хэш-индекса. Например:

test=# SELECT magic, version, ntuples, ffactor, bsize, bmsize, bmshift,
test-#     maxbucket, highmask, lowmask, ovflpoint, firstfree, nmaps, procid,
test-#     regexp_replace(spares::text, '(,0)*}', '}') as spares,
test-#     regexp_replace(mapp::text, '(,0)*}', '}') as mapp
test-# FROM hash_metapage_info(get_raw_page('con_hash_index', 0));
-[ RECORD 1 ]-------------------------------------------------​------------------------------
magic     | 105121344
version   | 4
ntuples   | 500500
ffactor   | 40
bsize     | 8152
bmsize    | 4096
bmshift   | 15
maxbucket | 12512
highmask  | 16383
lowmask   | 8191
ovflpoint | 28
firstfree | 1204
nmaps     | 1
procid    | 450
spares    | {0,0,0,0,0,0,1,1,1,1,1,1,1,1,3,4,4,4,45,55,58,59,​508,567,628,704,1193,1202,1204}
mapp      | {65}