2010-06-22 14 views
18

Postgres'te saklamak istediğim kayıt başına 7 8 bitlik tamsayı değerlerim var. Pg, en küçük tamsayı veri türü olan tek bir bayt tamsayı türü, SMALLINT veya 2 bayt sunmaz. Zaten 7 8-bit numaramı saklayabilirim ve uzayda tasarruf edebilir miyim?Postgres'te 1 bayt numara saklamak mümkün mü?

7 elemanlı bir dizi türü daha kompakt olabilir mi? Ya da 7 numaramın ikili bir temsilini yapmalıyım (örneğin, Perl'deki paketi kullanarak) ve bunu tek bir bytea alanında saklamalı mıyım?

Başka önerileriniz var mı?

cevap

17

PostgreSQL'deki herhangi bir satırın ek yükünün 23 bytes (HeapTupleHeaderData) olduğu göz önünde bulundurulduğunda, gerçekten çok az miktarda alanla ilgileniyorsanız, verilerinizi saklamak için yanlış yolu seçtiniz.

Daha karmaşık olan tüm türler kendi başlarına sahip olduklarından bağımsız olarak (bytea örneğin 4 baytlık 5 baytlık bir ek yük ekler), aradığınız şeyi başarmanın tek yolu bir bigint kullanmaktır (8 bayt), her bir değerin sayısal olarak kaydırılması ve sonuçların bir araya getirilmesi. Kodu daha kolay hale getirmek için bit string operations'u kullanarak yapabilirsiniz - bit dizgisi olarak hesaplayın, daha sonra depolamadan önce bigint'e dökün - ya da hızın daha iyi olmasını istiyorsanız sadece elle çarpın/ekleyin.

int2 = 256 * byte1 + byte2 
byte1 = int2/256 
byte2 = int2 % 256 

Bunlardan 7 bu şekilde depolanması halinde aynı fikri uzatabilirsiniz: Bir iki bayt yapıya birlikte iki bayt depolamak ve daha sonra onları tekrar geri almak nasıl Örneğin, burada. Geri alma ek yükü hala korkunç olacak, ancak aslında süreçte biraz yer kaplayacaksınız. Ancak sadece satır başlığına göre değil.

+3

her satırda 6 x 1 bayt tamsayı (?), 3 x 2 bayt tamsayı (SMALLINT) ve 2 x 4 bayt tamsayı (INT) vardır. Bu, satır başına toplam 20 bayt artı Pg'nin genel yüküdür. Pg sadece SMALLINT'leri en küçük değer olarak sağladığından, 6 1 bayt değerlerim 12 bayt alır. Bunlar için olası bir alternatif arıyorum. 120 milyar satırlık 6 baytlık bir tasarruf 670 GB civarındadır (eğer hesaplamam doğruysa). Yani, bu değerleri ayrı ayrı almam gerekiyor, bu yüzden fiyatı geri alma hızında ödeyebilirim. İkisini dengelemeye ihtiyacım var. 0,7 TB, daha büyük şemalarda çok büyük bir alan değildir. – punkish

2

Hiç bu değerleri kullanarak kayıtları arama Will: http://www.postgresql.org/docs/8.4/interactive/datatype-binary.html

da dize veri türleri vardır bit edilir?

Evet ise - int4 gibi normal veri tiplerini (veya 64bit mimarisinde iseniz bile int8) kullanın.

Değilse - önce kendinize sorun - bu değerleri Pg'de saklamanın amacı nedir? Bytea (karmaşık i/o) veya bitstrings (daha da karmaşık i/o) kullanabilirsiniz, ancak ne anlamı var? Kaç milyar kayıt yapacaksın? Daha küçük veri türünün daha az alan kullandığını kontrol ettiniz (ipucu: yok, kontrol et - veri hizalama sorunları var mı)? Daha küçük veri türünün daha hızlı olduğu izlenimi altında çalışıyorsunuz (bu değil. Aslında 32bit mimarisinde iki int4 değerinden iki int2 değerini karşılaştırmak daha karmaşıktır).

+1

Bazıları hakkında daha fazla bilgi sağlayarak önceden girişimde bulunabileceğim geçerli sorularınız var. 6 8 bitlik değerlerim var ve 120 milyar satır bekleniyor. Bu nedenle, mekânı olabildiğince muhafaza etme arzusu. – punkish

+4

Aslında int2'ye karşı int2 depolama alanı tasarrufu sağlıyor. 8.4'te test ettim ve tuple başına 7 x int2 = 38 bayt depoladım; 7 x char (1) = 41 bayt; 7 x int4 = 52 bayt. –

1

İlk önce yaklaşık 7, ancak şimdi 6 bayt soruyorsunuz. Altı adet 8 bitlik değer, MAC adres boyutuna ve PostgreSQL'in yerleşik macaddr'e tam olarak karşılık gelir. MAC sözdizimini f.i. kullanarak bu baytları ekleyebilirsiniz. A1-B2-C3-D4-E5-F6.

4

Değerini depolamak için yalnızca 1 bayt kullanan pg_catalog.char (başka notasyon - "char") türü vardır.

select pg_column_size('A'); 
pg_column_size 
---------------- 
       2 
(1 row) 

select pg_column_size('A'::"char"); 
pg_column_size 
---------------- 
       1 
(1 row) 
+1

"char" türü yalnızca 0'dan 127'ye kadar "sayılabilir". Bunu deneyin: 'select_series'den (i," char ") generate_series (0, 127) s (i)' den seçin. Şimdi 127 ile 128 arasında değiştirin. –

+4

@ClodoaldoNeto doğru değil, -128'den 127'ye kadar sayılabilir, select_series (-128, 127) s (i) 'den i, ascii (i ::" char ") i seçin – TruongSinh