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
ctidC 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, biginther durumda işe yarayacaktım .
Oyuncular
Orada kayıtlı hiçbir döküm için tidPostgres 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 float8sayı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;
intbunun 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_tidyorumladı.
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.