SELECT (ctid::text::point)[0]::bigint AS page_number FROM t;
Ваша загадка з моїм рішенням.
@bma вже натякнув щось подібне у коментарі. Ось ...
Обґрунтування типу
ctid
має тип tid
(ідентифікатор кортежу), викликаний ItemPointer
у коді С. За документацію:
Це тип даних стовпця системи ctid
. Ідентифікатор кортежу - це пара ( номер блоку , індекс кортежу в блоці ), який ідентифікує фізичне розташування рядка в його таблиці.
Сміливий акцент мій. І:
( ItemPointer
також відомий як CTID
)
Блок становить 8 КБ у стандартних установках. Максимальний розмір столу - 32 ТБ . Звідси логічно випливає, що номери блоків повинні містити щонайменше максимум (розрахунок зафіксовано відповідно до коментаря @Daniel):
SELECT (2^45 / 2^13)::int -- = 2^32 = 4294967294
Який би вписувався в непідписаний integer
. При подальшому дослідженні я знайшов у вихідному коді, що ...
блоки нумеруються послідовно, 0 до 0xFFFFFFFE .
Сміливий акцент мій. Що підтверджує перший розрахунок:
SELECT 'xFFFFFFFE'::bit(32)::int8 -- max page number: 4294967294
Postgres використовує підписане ціле число, і тому один біт короткий. Я не зміг визначити, чи зміщено подання тексту на вміст підписаного цілого числа. Поки хтось не зможе це зрозуміти, я б повернувся до цього bigint
, що працює в будь-якому випадку.
У ролях
Там немає не з'являлися лита для tid
типу в Postgres 9.3:
SELECT *
FROM pg_cast
WHERE castsource = 'tid'::regtype
OR casttarget = 'tid'::regtype;
castsource | casttarget | castfunc | castcontext | castmethod
------------+------------+----------+-------------+------------
(0 rows)
Ви все ще можете подати в text
. У Postgres є текстове подання для всього :
Іншим важливим винятком є те, що "автоматичні перетворення вводу / виводу", виконані за допомогою власних функцій вводу / виводу типу даних для перетворення в текст або з інших типів рядків, явно не представлені в
pg_cast
.
Текстове подання відповідає тексту точки, яка складається з двох float8
чисел, що вказується без втрат.
Ви можете отримати доступ до першого числа точки з індексом 0. Передайте bigint
. Войла.
Продуктивність
Я провів швидкий тест на столі з 30-кратними рядами (найкраще з 5) на пару альтернативних виразів, які вам прийшли в голову, включаючи ваш оригінал:
SELECT (ctid::text::point)[0]::int -- 25 ms
,right(split_part(ctid::text, ',', 1), -1)::int -- 28 ms
,ltrim(split_part(ctid::text, ',', 1), '(')::int -- 29 ms
,(ctid::text::t_tid).page_number -- 31 ms
,(translate(ctid::text,'()', '{}')::int[])[1] -- 45 ms
,(replace(replace(ctid::text,'(','{'),')','}')::int[])[1] -- 51 ms
,substring(right(ctid::text, -1), '^\d+')::int -- 52 ms
,substring(ctid::text, '^\((\d+),')::int -- 143 ms
FROM tbl;
int
замість bigint
цього, в основному, не має значення для цілі тесту. Я не повторювався за bigint
.
Кидок до t_tid
спирається на певний користувачем складеного типу, як @Jake прокоментував.
Суть цього: Кастинг, як правило, швидше, ніж маніпуляція зі струнами. Регулярні вирази дорогі. Вищевказане рішення є найкоротшим та найшвидшим.