SELECT (ctid::text::point)[0]::bigint AS page_number FROM t;
Sizin keman benim çözeltisi ile.
@bma zaten bir yorumda benzer bir şey ima etti. Burada bir ...
Tür için gerekçe
ctid
C kodunda tid
çağrılan tiptir (grup tanımlayıcısı) ItemPointer
. Belgelere göre:
Bu, sistem sütununun veri türüdür ctid
. Bir grup kimliği, satırın tablosundaki fiziksel konumunu tanımlayan bir çifttir ( blok numarası , blok içindeki grup dizini ).
Cesur vurgu benim. Ve:
( ItemPointer
, olarak da bilinir CTID
)
Standart kurulumlarda bir blok 8 KB'dir . Maksimum Tablo Boyutu 32 TB'dir . Mantıksal olarak, blok numaralarının en az bir sayıda (@Daniel tarafından yapılan yoruma göre sabitlenmiş hesaplama) barındırması gerektiği izlenir:
SELECT (2^45 / 2^13)::int -- = 2^32 = 4294967294
Hangi imzasız bir sığacak integer
. Daha fazla araştırma üzerine kaynak kodunda buldum ...
bloklar sırayla 0 ile 0xFFFFFFFE arasında numaralandırılır .
Cesur vurgu benim. İlk hesaplamayı doğrulayan:
SELECT 'xFFFFFFFE'::bit(32)::int8 -- max page number: 4294967294
Postgres imzalı tamsayı kullanır ve bu nedenle bir bit kısadır. Metin temsilinin işaretli tamsayıyı alacak şekilde kaydırılıp kaydırılmadığını henüz anlayamadım. Birisi bunu temizleyene kadar, bigint
her durumda işe yarayacaktım .
Oyuncular
Orada kayıtlı hiçbir döküm için tid
Postgres 9.3 tip:
SELECT *
FROM pg_cast
WHERE castsource = 'tid'::regtype
OR casttarget = 'tid'::regtype;
castsource | casttarget | castfunc | castcontext | castmethod
------------+------------+----------+-------------+------------
(0 rows)
Hala yayınlayabilirsiniz text
. Postgres'teki her şey için bir metin temsili vardır :
Bir başka önemli istisna, metin veya diğer dize türlerine dönüştürmek veya veri türünden dönüştürmek için bir veri türünün kendi G / Ç işlevleri kullanılarak gerçekleştirilen "otomatik G / Ç dönüştürme dökümleri" nin açıkça temsil edilmemesidir
pg_cast
.
Metin gösterimi, iki float8
sayıdan oluşan bir noktanın dökümüyle eşleşmez;
0 noktasından bir noktanın ilk numarasına erişebilirsiniz bigint
. Voila.
Verim
Orijinaliniz de dahil olmak üzere aklınıza gelen birkaç alternatif ifadede 30k satırlı (5'in en iyisi) bir tablo üzerinde hızlı bir test yaptım:
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
bunun yerine bigint
, çoğunlukla testin amacı ile alakasız. Ben tekrar etmedim bigint
. @Jake gibi kullanıcı tanımlı bir kompozit tür üzerine inşa edilecek
döküm t_tid
yorumladı.
Bunun özü: Döküm, dizi manipülasyonundan daha hızlı olma eğilimindedir. Düzenli ifadeler pahalıdır. Yukarıdaki çözüm en kısa ve en hızlıdır.