テーブルの各行には、行の物理的な場所を表すctid
タイプの システム列tid
があります。
_create table t(id serial); insert into t default values; insert into t default values;
_
_select ctid , id from t;
_ctid | id :- -: (0,1)| 1 (0,2)| 2
dbfiddle ---(ここ
最も適切なタイプのctid
からページ番号のみを取得する最良の方法は何ですか(例integer
、bigint
またはnumeric(1000,0)
)?
私が考えることができる唯一の方法 は非常に醜いです。
SELECT (ctid::text::point)[0]::bigint AS page_number FROM t;
@bmaはすでにコメントで同様のことを示唆しています。がここにあります ...
ctid
のタイプはtid
(タプル識別子)で、Cコードでは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
は繰り返しませんでした。t_tid
へのキャストは、@ Jakeがコメントしたように、ユーザー定義の複合型に基づいています。
要点:キャストは文字列操作よりも高速になる傾向があります。正規表現は高価です。上記のソリューションが最短で最速です。