SELECT (ctid::text::point)[0]::bigint AS page_number FROM t;
您在摆弄我的解决方案。
@bma已经在评论中暗示了类似的内容。这里有一个 ...
类型的基本原理
ctid
是类型tid
(元组标识符),ItemPointer
在C代码中调用。每个文档:
这是系统列的数据类型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使用带符号的整数,因此短了一位。但是,我无法确定文本表示是否已移动以容纳带符号的整数。在有人可以解决之前,我会退回到bigint
,无论如何都可以。
投
有没有注册投了tid
在Postgres的9.3类型:
SELECT *
FROM pg_cast
WHERE castsource = 'tid'::regtype
OR casttarget = 'tid'::regtype;
castsource | casttarget | castfunc | castcontext | castmethod
------------+------------+----------+-------------+------------
(0 rows)
您仍然可以投射到text
。有一个在Postgres的一切文本表示:
另一个重要的例外是,“自动I / O转换强制转换”未使用明确表示,“自动I / O转换强制转换”是使用数据类型自己的I / O函数在文本或其他字符串类型之间进行转换
pg_cast
。
文本表示与包含两个float8
数字的点的表示形式匹配,该表示形式是无损的。
您可以使用索引0访问点的第一个数字bigint
。Voilá。
性能
我在一个包含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注释。
要点:铸造往往比字符串处理要快。正则表达式很昂贵。以上解决方案是最短和最快的。