Каждая строка в таблице имеет системный столбец ctid
типа, tid
который представляет физическое местоположение строки:
create table t(id serial); insert into t default values; insert into t default values;
select ctid , id from t;
Ctid | Я бы : ---- | -: (0,1) | 1 (0,2) | 2
dbfiddle здесь
Как лучше всего получить только номер страницы из ctid
наиболее подходящего типа (например integer
, bigint
или numeric(1000,0)
)?
Единственным способом я могу думать очень некрасиво.
postgresql
postgresql-9.4
datatypes
cast
data-pages
Джек Дуглас
источник
источник
select ct[0], ct[1] from (select ctid::text::point as ct from pg_class where ...) y;
Ответы:
Твоя скрипка с моим решением.
@bma уже намекнул нечто подобное в комментарии. Вот ...
Обоснование типа
ctid
имеет типtid
(идентификатор кортежа), вызываемыйItemPointer
в коде C. По документации:Жирный акцент мой. И:
Блок составляет 8 КБ в стандартных установках. Максимальный размер таблицы составляет 32 ТБ . Логически следует, что номера блоков должны соответствовать как минимум максимуму (расчет фиксируется согласно комментарию @Daniel):
Который вписался бы в неподписанного
integer
. При дальнейшем расследовании я обнаружил в исходном коде, что ...Жирный акцент мой. Что подтверждает первый расчет:
Postgres использует целое число со знаком и, следовательно, на один бит меньше. Я пока не могу определить, смещено ли текстовое представление для размещения целого числа со знаком. Пока кто-нибудь не сможет это прояснить, я бы отступил
bigint
, что работает в любом случае.В ролях
В Postgres 9.3 не зарегистрировано приведение
tid
типа:Вы все еще можете бросить на
text
. В Postgres есть текстовое представление для всего :Текстовое представление соответствует представлению точки, состоящей из двух
float8
чисел, которое приведено без потерь.Вы можете получить доступ к первому номеру точки с индексом 0. Приведение к
bigint
. Вуаля.Производительность
Я провел быстрый тест для таблицы с 30 тыс. Строк (лучше всего из 5) на нескольких альтернативных выражениях, которые пришли в голову, включая ваш исходный:
int
вместо этогоbigint
, в основном не имеет значения для целей теста. Я не повторил дляbigint
.Приведение к
t_tid
основывается на пользовательском составном типе, как, например, прокомментировал @Jake.Суть этого: кастинг, как правило, быстрее, чем манипуляции со строками. Регулярные выражения стоят дорого. Вышеуказанное решение является самым коротким и быстрым.
источник
ctid
6 байт с 4 на странице и 2 для строки. Я волновался по поводу кастинга,float
но, думаю, мне не нужно понимать то, что вы здесь говорите. Похоже, что пользовательский составной тип намного медленнее, чем при использованииpoint
, вы тоже это нашли?bigint
. Рассмотрим обновление.point
и обратноint8
все еще быстрее). Приведение к предопределенным типам всегда будет немного быстрее. Я добавил его в свой тест для сравнения. Я бы сделал это,(page_number bigint, row_number integer)
чтобы быть уверенным.2^40
составляет всего 1 ТБ, а не 32 ТБ, то есть2^45
, что делится на,2^13
дает2^32
, следовательно, полные 32 бита, необходимые для номера страницы.bigint
для blkno