SELECT (ctid::text::point)[0]::bigint AS page_number FROM t;
私の解決策とあなたのフィドル。
@bmaはすでにコメントで似たようなことをほのめかしています。がここにあります ...
タイプの根拠
ctid
Cコードtid
で呼び出されるタイプ(タプル識別子)ItemPointer
です。ドキュメントごと:
これはシステム列のデータ型ですctid
。タプルIDは、テーブル内の行の物理的な場所を識別するペア(ブロック番号、ブロック内のタプルインデックス)です。
大胆な強調鉱山。そして:
(ItemPointer
、別名CTID
)
標準インストールでは、ブロックは8 KBです。最大テーブルサイズは32 TBです。論理的には、ブロック番号は少なくとも最大(@Danielのコメントに従って修正された計算)に対応する必要があります。
SELECT (2^45 / 2^13)::int -- = 2^32 = 4294967294
これは符号なしに収まりinteger
ます。さらに調査すると、ソースコードで次のことがわかりました ...
ブロックには、0〜0xFFFFFFFEの順に番号が付けられます。
大胆な強調鉱山。最初の計算を確認します:
SELECT 'xFFFFFFFE'::bit(32)::int8 -- max page number: 4294967294
Postgresは符号付き整数を使用するため、1ビット短いです。符号付き整数に対応するためにテキスト表現がシフトされるかどうかは、まだ特定できませんでした。誰かがこれをクリアできるまで、私はに戻りbigint
、どの場合でも機能します。
キャスト
Postgres 9.3のタイプに登録されているキャストはありませんtid
。
SELECT *
FROM pg_cast
WHERE castsource = 'tid'::regtype
OR casttarget = 'tid'::regtype;
castsource | casttarget | castfunc | castcontext | castmethod
------------+------------+----------+-------------+------------
(0 rows)
それでもにキャストできtext
ます。Postgresにはすべてのテキスト表現があります:
もう1つの重要な例外は、「自動I / O変換キャスト」、データ型の独自のI / O関数を使用してテキストまたは他の文字列型との間で変換を実行するものは、で明示的に表されないこと
pg_cast
です。
テキスト表現は、2つのfloat8
数字で構成されるポイントの表現と一致し、キャストはロスレスです。
インデックス0でポイントの最初の番号にアクセスできますbigint
。にキャストします。ボイラ。
性能
私は、あなたのオリジナルを含め、思いついたいくつかの代替式で、3万行(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
。@Jakeがコメントしたように、ユーザー定義の複合型
にt_tid
基づいてビルドするキャスト。
要点:キャストは文字列操作よりも高速になる傾向があります。正規表現は高価です。上記のソリューションは、最短かつ最速です。