pageinspect — низкоуровневый анализ страниц базы данных
Эта страница переведена при помощи нейросети GigaChat.
Модуль 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
отображает поля, общие для всех страниц кучи и индекса PostgreSQL.
Образ страницы, полученный с помощью 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.
Функции для исследования кучи
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
для объяснений возвращаемых имен флагов.
Функции для индексов 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_multi_page_stats(relname text, blkno bigint, blk_count bigint) returns setof record
: bt_multi_page_stats
возвращает ту же информацию, что и bt_page_stats
, но делает это для каждой страницы диапазона страниц начиная с blkno
и продолжая до blk_count
страниц. Если blk_count
отрицательный, информация обо всех страницах от blkno
до конца индекса будет включена в отчет. Например:
test=# SELECT * FROM bt_multi_page_stats('pg_proc_oid_index', 5, 2);
-[ RECORD 1 ]-+-----
blkno | 5
type | l
live_items | 367
dead_items | 0
avg_item_size | 16
page_size | 8192
free_size | 808
btpo_prev | 4
btpo_next | 6
btpo_level | 0
btpo_flags | 1
-[ RECORD 2 ]-+-----
blkno | 6
type | l
live_items | 367
dead_items | 0
avg_item_size | 16
page_size | 8192
free_size | 808
btpo_prev | 5
btpo_next | 7
btpo_level | 0
btpo_flags | 1
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
для хранения закодированной информации о каждом кортеже, хотя кортежи на листовой странице часто хранят TID кучи непосредственно в поле ctid
. tids
– это список TID, хранящихся в виде списка сообщений.
На внутренней странице (она здесь не показана), компонент номера блока в ctid содержит «ссылку вниз», который представляет собой номер блока другой страницы в самом индексе. Часть смещения (второе число) ctid
хранит закодированную информацию о кортеже, такую как количество присутствующих столбцов (обрезка суффикса может удалить ненужные столбцы суффиксов). Обрезанные столбцы рассматриваются как имеющие значение «минус бесконечность».
htid
показывает TID кучи для кортежа независимо от базового представления кортежа. Это значение может совпадать с ctid
, или может быть декодировано из альтернативных представлений, используемых кортежами списка сообщений и кортежами внутренних страниц. Кортежи во внутренних страницах обычно имеют усеченный столбец TID уровня реализации кучи, что представлено значением NULL
htid
.
Обратите внимание, что первый элемент на любой странице, не являющейся самой правой (любая страница с ненулевым значением в поле btpo_next
) является ключом страницы «верхний ключ», что означает, что его data
служит верхней границей для всех элементов, появляющихся на странице, тогда как его ctid
поле не указывает на другой блок. Кроме того, на внутренних страницах первый реальный элемент данных (первый элемент, который не является высоким ключом) надежно имеет все столбцы, усеченные до нуля, оставляя нулевое значение в его data
поле. Однако такой элемент действительно имеет допустимую нисходящую ссылку в своем ctid
поле.
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 | empty | value
------------+--------+--------+----------+----------+-------------+-------+--------------
137 | 0 | 1 | t | f | f | f |
137 | 0 | 2 | f | f | f | f | {1 .. 88}
138 | 4 | 1 | t | f | f | f |
138 | 4 | 2 | f | f | f | f | {89 .. 176}
139 | 8 | 1 | t | f | f | f |
139 | 8 | 2 | f | 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, правая ссылка и тип страницы. Например:
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
BLOB. Поскольку она не пытается декодировать ключ, ей не нужно знать, какой индекс участвует. Например:
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 | \x00000100ffff28000000000000c064400000000000c06440000000000000f03f000000000000f03f
2 | (2,65535) | 40 | f | \x00000200ffff28000000000000c074400000000000c074400000000000e064400000000000e06440
3 | (3,65535) | 40 | f | \x00000300ffff28000000000000207f400000000000207f400000000000d074400000000000d07440
4 | (4,65535) | 40 | f | \x00000400ffff28000000000000c084400000000000c084400000000000307f400000000000307f40
5 | (5,65535) | 40 | f | \x00000500ffff28000000000000f089400000000000f089400000000000c884400000000000c88440
6 | (6,65535) | 40 | f | \x00000600ffff28000000000000208f400000000000208f400000000000f889400000000000f88940
7 | (7,65535) | 40 | f | \x00000700ffff28000000000000408f400000000000408f400000000000288f400000000000288f40
(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}