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
ctid
ist vom Typ tid
(Tupelidentifikator), der ItemPointer
im 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:
( ItemPointer
auch 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 tid
Typ 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 float8
Zahlen 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;
int
statt bigint
hier, meist irrelevant für den Testzweck. Ich habe es nicht wiederholt bigint
.
Die Besetzung t_tid
baut 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.