Jac*_*las 19 postgresql data-pages datatypes cast postgresql-9.4
表中的每一行都有一个系统列 ctid
,其类型tid
表示该行的物理位置:
Run Code Online (Sandbox Code Playgroud)create table t(id serial); insert into t default values; insert into t default values;
Run Code Online (Sandbox Code Playgroud)select ctid , id from t;
ctid | ID :---- | -: (0,1) | 1 (0,2) | 2
dbfiddle在这里
从ctid
最合适的类型(例如integer
,bigint
或numeric(1000,0)
)中获取页码的最佳方法是什么?
在我能想到的唯一的办法是非常难看。
Erw*_*ter 26
SELECT (ctid::text::point)[0]::bigint AS block_number FROM t;
Run Code Online (Sandbox Code Playgroud)
db<>在这里摆弄
@bma 在他的评论中提出了类似的建议。这里有一个 ...
ctid
是类型tid
(元组标识符),ItemPointer
在 C 语言源代码中调用。手册:
这是系统列的数据类型
ctid
。元组 ID 是一对(块编号,块内的元组索引),用于标识行在其表中的物理位置。
大胆强调我的。和:
(
ItemPointer
, 也称为CTID
)
在标准安装中,一个块为8 KB。最大表大小为32 TB。从逻辑上讲,块编号必须至少容纳最大值(根据@Daniel 的评论固定):
SELECT (2^45 / 2^13)::int -- = 2^32 = 4294967294
Run Code Online (Sandbox Code Playgroud)
这将适合 unsigned integer
。在进一步调查中,我在源代码中发现......
块按顺序编号,从0 到 0xFFFFFFFE。
大胆强调我的。这证实了第一个计算:
SELECT 'xFFFFFFFE'::bit(32)::int8 -- max page number: 4294967294
Run Code Online (Sandbox Code Playgroud)
Postgres 使用有符号整数,因此有点短。然而,我无法确定文本表示是否被移动以适应有符号整数。在有人解决这个问题之前,我会退回到bigint
,这在任何情况下都有效。
有没有注册投了tid
在Postgres的9.3型(从Postgres 13依然如此):
SELECT *
FROM pg_cast
WHERE castsource = 'tid'::regtype
OR casttarget = 'tid'::regtype;
castsource | casttarget | castfunc | castcontext | castmethod
------------+------------+----------+-------------+------------
(0 rows)
Run Code Online (Sandbox Code Playgroud)
您仍然可以投射到text
. Postgres 中的每种类型都有一个文本表示:
另一个重要的例外是“自动 I/O 转换转换”,即使用数据类型自己的 I/O 函数执行的转换为文本或其他字符串类型的转换,在
pg_cast
.
文本表示匹配由两个float8
数字组成的点的表示,该点是无损的。
您可以访问索引为 0 的点的第一个数字。转换为bigint
。瞧。
我在 Postgres 9.4 中对一个包含 30k 行(最好是 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;
Run Code Online (Sandbox Code Playgroud)
int
而不是bigint
,与测试目的大多无关。我最终在bigint
具有 50k 行的表上重复了 Postgres 13 中的测试。结果大体相同!
t_tid
强制转换建立在用户定义的复合类型上,就像@Jake 评论的那样。
它的要点:转换往往比字符串操作更快。正则表达式很昂贵。上面的解决方案是最短和最快的。
归档时间: |
|
查看次数: |
14004 次 |
最近记录: |