SELECT (ctid::text::point)[0]::bigint AS page_number FROM t;
Ihre Geige mit meiner Lösung.
@bma hat bereits in einem Kommentar etwas Ähnliches angedeutet. Hier ist ein ...
Begründung für den Typ
ctidist vom Typ tid(Tupelidentifikator), der ItemPointerim C-Code aufgerufen wird . Per Dokumentation:
Dies ist der Datentyp der Systemspalte ctid. Eine Tupel-ID ist ein Paar ( Blocknummer , Tupelindex innerhalb des Blocks ), das die physische Position der Zeile in ihrer Tabelle angibt.
Meine kühne Betonung. Und:
( ItemPointerauch bekannt als CTID)
Ein Block hat in Standardinstallationen eine Größe von 8 KB . Die maximale Tabellengröße beträgt 32 TB . Es folgt logischerweise, dass Blocknummern mindestens ein Maximum von (Berechnung gemäß Kommentar von @Daniel festgelegt) aufnehmen müssen:
SELECT (2^45 / 2^13)::int -- = 2^32 = 4294967294
Welches würde in ein unsigniertes passen integer. Bei weiteren Nachforschungen stellte ich im Quellcode fest, dass ...
Blöcke werden fortlaufend von 0 bis 0xFFFFFFFE nummeriert .
Meine kühne Betonung. Was die erste Berechnung bestätigt:
SELECT 'xFFFFFFFE'::bit(32)::int8 -- max page number: 4294967294
Postgres verwendet eine Ganzzahl mit Vorzeichen und ist daher ein bisschen kurz. Ich konnte noch nicht festlegen, ob die Textdarstellung verschoben wird, um eine Ganzzahl mit Vorzeichen aufzunehmen. Bis jemand dies aufklären kann, würde ich zurück fallen bigint, was auf jeden Fall funktioniert.
Besetzung
Es ist keine Besetzung für den tidTyp in Postgres 9.3 registriert :
SELECT *
FROM pg_cast
WHERE castsource = 'tid'::regtype
OR casttarget = 'tid'::regtype;
castsource | casttarget | castfunc | castcontext | castmethod
------------+------------+----------+-------------+------------
(0 rows)
Sie können immer noch zu besetzen text. Es gibt eine Textdarstellung für alles in Postgres :
Eine weitere wichtige Ausnahme ist, dass "automatische E / A-Konvertierungskonvertierungen", bei denen die E / A-Funktionen eines Datentyps zum Konvertieren in oder aus Text oder anderen Zeichenfolgentypen verwendet werden, in nicht explizit dargestellt werden
pg_cast.
Die Textdarstellung entspricht der eines Punktes, der aus zwei float8Zahlen besteht, die verlustfrei gewirkt werden.
Sie können auf die erste Nummer eines Punktes mit Index 0 zugreifen bigint. Voilá.
Performance
Ich habe einen Kurztest an einer Tabelle mit 30.000 Zeilen (Best-of-5) mit ein paar alternativen Ausdrücken durchgeführt, die mir in den Sinn kamen, einschließlich Ihres Originals:
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;
intstatt biginthier, meist irrelevant für den Testzweck. Ich habe es nicht wiederholt bigint.
Die Besetzung t_tidbaut auf einem benutzerdefinierten zusammengesetzten Typ auf, wie beispielsweise @Jake commented.
Das Wesentliche dabei: Das Casting ist in der Regel schneller als die Manipulation von Saiten. Reguläre Ausdrücke sind teuer. Die obige Lösung ist am kürzesten und schnellsten.