2013-04-13 6 views
8

Ich möchte den MD5-Nachrichtenauszug einer Zeichenfolge als Primärschlüssel einer Tabelle verwenden. Was Datentyp sollte ich für ein solches Feld verwenden? Was select und insert Aussagen sollte ich für das Feld schreiben?postgresql: Datentyp für MD5 Message Digest?

Antwort

10

Die md5 Hash als bytea nur 16 Byte anstelle von 32 für die Hexa-Darstellung verwenden:

create table t (d bytea); 
insert into t (d) values 
    (digest('my_string', 'md5')), 
    (decode(md5('my_string'), 'hex')); 

Beiden obigen Formen aber funktionieren die einfachere digest Funktion es ist notwendig, verwenden, um die pgcrypto Erweiterung zu installieren als Superuser:

create extension pgcrypto; 

Verwenden Sie die digest Funktion oder die Kombination von decode und md5 wie oben für eine bestimmte Zeichenfolge zu suchen:

select 
    octet_length(d) ba_length, 
    pg_column_size(d) ba_column, 
    encode(d, 'hex') hex_representation, 
    octet_length(encode(d, 'hex')) h_length, 
    pg_column_size(encode(d, 'hex')) h_column 
from t 
where d = digest('my_string', 'md5') 
; 
ba_length | ba_column |  hex_representation  | h_length | h_column 
-----------+-----------+----------------------------------+----------+---------- 
     16 |  17 | 3d212b21fad7bed63c1fb560c6a5c5d0 |  32 |  36 
     16 |  17 | 3d212b21fad7bed63c1fb560c6a5c5d0 |  32 |  36 

Der Wert pg_column_size ist die Speichergröße. Es ist weniger als die Hälfte für die bytea im Vergleich zu der Hexa-Darstellung.

1

bytea hat einen Ein-Byte-Overhead, aber mit Auffüllung auf acht Bytes führt dies zu erheblichen Verschwendung.

Verwenden Sie stattdessen den Typ uuid, der nur 16 Byte verwendet. Sie müssen etwas wie REPLACE(md5::text, '-', '') as md5 verwenden, wenn Sie es auswählen, aber das sollte eine schnelle Operation sein.

+0

Haben Sie eine Referenz für 'Padding bis 8 Bytes'? Alle [die Dokumente sagen] (http://www.postgresql.org/docs/9.4/static/datatype-binary.html) ist die Speichergröße = "1 oder 4 Bytes plus die tatsächliche binäre Zeichenfolge" –

+0

Zwei Probleme: a) Sie speichern 1 + 16 = 17 Bytes, die nachfolgende Spalte wird mit typalign in [pg_type] (http://www.postgresql.org/docs/9.0/static/catalog-pg-type.html) aufgefüllt, b) Siehe [diese Frage] (http://stackoverflow.com/questions/2966524/calculating-and-saving-space-in-postgresql) bezüglich MAXALIGN und der [Seitenlayout-Referenz] (http://www.postgresql.org) /docs/9.4/static/storage-page-layout.html) für * row * alignment. ["Die tatsächlichen Benutzerdaten (Spalten der Zeile) beginnen bei dem durch t_hoff angegebenen Offset, der immer ein Vielfaches der MAXALIGN-Distanz für die Plattform sein muss." == 8 auf x64]. – GreenReaper

+0

In diesem speziellen Fall wäre die Zeilenplatznutzung wahrscheinlich 23 + 1 (Zeilenkopf + Nullkopf für bis zu 8 Spalten) + 4 (ba_length) + 4 (ba_column) + 1 + 16 (hex_representation) + 3 (Ausrichtungsauffüllung für h_length) + 4 (h_length) + 4 (h_column) = 60 + 4 (Zeilenauffüllung). So erhalten Sie 1 + 3 + 4 = 8 Bytes mehr als mit UUID. Fazit: Wenn Sie sich um Platz kümmern, müssen Sie sich um Ihr Zeilenlayout kümmern. In der Regel ist es relativ optimal, große Felder zuerst zu setzen. Wenn es jedoch größer als 8 Byte ist, können Sie es noch einmal überdenken. – GreenReaper