SELECT (ctid::text::point)[0]::bigint AS page_number FROM t;
Fiddle của bạn với giải pháp của tôi.
@bma đã gợi ý một cái gì đó tương tự trong một bình luận. Đây là ...
Cơ sở lý luận cho các loại
ctid
là loại tid
(định danh tuple), được gọi ItemPointer
trong mã C. Mỗi tài liệu:
Đây là kiểu dữ liệu của cột hệ thống ctid
. ID tuple là một cặp ( số khối , chỉ số tuple trong khối ) xác định vị trí vật lý của hàng trong bảng của nó.
Nhấn mạnh đậm của tôi. Và:
( ItemPointer
, còn được gọi là CTID
)
Một khối là 8 KB trong cài đặt tiêu chuẩn. Kích thước bảng tối đa là 32 TB . Theo logic, số khối phải chứa tối thiểu tối đa (tính toán cố định theo nhận xét của @Daniel):
SELECT (2^45 / 2^13)::int -- = 2^32 = 4294967294
Mà sẽ phù hợp với một không dấu integer
. Khi điều tra sâu hơn, tôi tìm thấy trong mã nguồn ...
các khối được đánh số liên tục, 0 đến 0xFFFFFFFE .
Nhấn mạnh đậm của tôi. Xác nhận tính toán đầu tiên:
SELECT 'xFFFFFFFE'::bit(32)::int8 -- max page number: 4294967294
Postgres sử dụng số nguyên đã ký và do đó ngắn một bit. Tuy nhiên, tôi không thể xác định liệu biểu diễn văn bản có bị dịch chuyển để phù hợp với số nguyên đã ký hay không. Cho đến khi ai đó có thể làm rõ điều này, tôi sẽ quay trở lại bigint
, hoạt động trong mọi trường hợp.
Diễn viên
Không có diễn viên nào được đăng ký cho tid
loại trong Postgres 9.3:
SELECT *
FROM pg_cast
WHERE castsource = 'tid'::regtype
OR casttarget = 'tid'::regtype;
castsource | casttarget | castfunc | castcontext | castmethod
------------+------------+----------+-------------+------------
(0 rows)
Bạn vẫn có thể sử dụng text
. Có một văn bản đại diện cho mọi thứ trong Postgres :
Một ngoại lệ quan trọng khác là "phôi chuyển đổi I / O tự động", được thực hiện bằng các hàm I / O của loại dữ liệu để chuyển đổi sang hoặc từ văn bản hoặc các loại chuỗi khác, không được trình bày rõ ràng trong
pg_cast
.
Biểu diễn văn bản khớp với điểm của một điểm, bao gồm hai float8
số, biểu diễn đó không mất.
Bạn có thể truy cập số đầu tiên của một điểm bằng chỉ số 0. Truyền tới bigint
. Voilá.
Hiệu suất
Tôi đã chạy thử nghiệm nhanh trên một bảng có 30k hàng (tốt nhất là 5) trên một vài biểu thức thay thế xuất hiện trong đầu, bao gồm cả bản gốc của bạn:
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
thay vì bigint
ở đây, chủ yếu là không liên quan cho mục đích thử nghiệm. Tôi đã không lặp lại cho bigint
.
Dàn diễn viên t_tid
xây dựng trên loại hỗn hợp do người dùng định nghĩa, như @Jake đã nhận xét.
Ý chính của nó: Đúc có xu hướng nhanh hơn thao tác chuỗi. Biểu thức thông thường là đắt tiền. Giải pháp trên là ngắn nhất và nhanh nhất.