F.30. pageinspect#

F.30. pageinspect

F.30. pageinspect

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

F.30.1. Общие функции

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 показывает поля, которые общие для всех страниц кучи и индекса Tantor SE.

Изображение страницы, полученное с помощью функции 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));

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

См. src/backend/storage/freespace/README для получения дополнительной информации о структуре страницы FSM.

F.30.2. Функции кучи

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 для объяснения возвращаемых полей.

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

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 для объяснения возвращаемых имен флагов.

F.30.3. Функции 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-ов длиной 6 байтов). Также есть кортеж high key с номером itemoffset равным 1. ctid используется для хранения закодированной информации о каждом кортеже в этом примере, хотя кортежи листовых страниц часто хранят непосредственно в поле ctid ссылку на кучу. tids - это список TID-ов, хранящихся в виде списка публикаций.

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

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

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

Для получения более подробной информации о структуре индексов B-дерева, см. Раздел 65.4.1. Для получения более подробной информации о дедупликации и списке публикаций, см. Раздел 65.4.3.

bt_page_items(page bytea) returns setof record

Также возможно передать страницу в качестве значения типа bytea в функцию bt_page_items. В качестве аргумента следует передать изображение страницы, полученное с помощью функции 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)

Все остальные детали остаются такими же, как объяснено в предыдущем пункте.

F.30.4. Функции 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 для получения подробной информации.

F.30.5. Функции 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)

F.30.6. Функции 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)=("(185,185),(1,1)")
          2 | (2,65535) |      40 | f    | (p)=("(370,370),(186,186)")
          3 | (3,65535) |      40 | f    | (p)=("(555,555),(371,371)")
          4 | (4,65535) |      40 | f    | (p)=("(740,740),(556,556)")
          5 | (5,65535) |      40 | f    | (p)=("(870,870),(741,741)")
          6 | (6,65535) |      40 | f    | (p)=("(1000,1000),(871,871)")
(6 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)

F.30.7. Функции хеширования

hash_page_type(page bytea) returns text

hash_page_type возвращает тип страницы данного индекса HASH. Например:

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 возвращает информацию о странице корзины или переполнения HASH индекса. Например:

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 возвращает информацию о данных, хранящихся в корзине или переполненной странице индексной страницы типа HASH. Например:

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 показывает статус бита в странице битовой карты для конкретной переполненной страницы индекса HASH. Например:

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 возвращает информацию, хранящуюся на метастранице индекса HASH. Например:

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}