Le type de données uuid
est parfaitement adapté à la tâche. Il n'occupe que 16 octets, contre 37 octets en RAM pour la représentation varchar
ou text
. (Ou 33 octets sur le disque, mais le nombre impair nécessiterait un bourrage dans de nombreux cas pour le rendre efficacement à 40 octets.) Et le uuid
type présente quelques avantages supplémentaires.
Exemple:
SELECT md5('Store hash for long string, maybe for index?')::uuid AS md5_hash
Détails et plus d'explications:
Vous pourriez envisager d'autres fonctions de hachage (moins chères) si vous n'avez pas besoin du composant cryptographique de md5, mais j'utiliserais md5 pour votre cas d'utilisation (la plupart du temps en lecture seule).
Un mot d' avertissement : pour votre cas ( immutable once written
), une PK dépendant de la fonctionnalité (pseudo-naturelle) convient. Mais la même chose serait une douleur où les mises à jour text
sont possibles. Pensez à corriger une faute de frappe: le PK et tous les index dépendants, les colonnes FK dozens of other tables
et autres références devraient également changer. Ballonnement des tables et des index, problèmes de verrouillage, mises à jour lentes, références perdues, ...
Si text
peut changer en fonctionnement normal, une PK de substitution serait un meilleur choix. Je suggère une bigserial
colonne (plage -9223372036854775808 to +9223372036854775807
- neuf cent vingt-trois cent vingt-trois quadrillions trois cent soixante-douze trillions trente-six milliards ) de valeurs distinctes billions of rows
. Peut-être une bonne idée dans tous les cas: 8 au lieu de 16 octets pour des dizaines de colonnes et d'index FK!). Ou un UUID aléatoire pour des cardinalités beaucoup plus grandes ou des systèmes distribués. Vous pouvez toujours stocker md5 (en tant que uuid
) en plus pour trouver rapidement des lignes dans la table principale à partir du texte d'origine. En relation:
En ce qui concerne votre question :
Pour répondre au commentaire de @ Daniel : Si vous préférez une représentation sans traits d'union, supprimez-les pour affichage:
SELECT replace('90b7525e-84f6-4850-c2ef-b407fae3f271', '-', '')
Mais je ne me dérangerais pas. La représentation par défaut est très bien. Et le problème n'est vraiment pas la représentation ici.
Si d'autres parties ont une approche différente et ajoutent des cordes sans trait d'union, ce n'est pas un problème non plus. Postgres accepte plusieurs représentations textuelles raisonnables comme entrée pour a uuid
. La documentation :
PostgreSQL accepte également les autres formes de saisie suivantes: utilisation de chiffres en majuscules, format standard entouré d'accolades, suppression de tout ou partie des tirets, ajout d'un trait d'union après tout groupe de quatre chiffres. Les exemples sont:
A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11
{a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11}
a0eebc999c0b4ef8bb6d6bb9bd380a11
a0ee-bc99-9c0b-4ef8-bb6d-6bb9-bd38-0a11
{a0eebc99-9c0b4ef8-bb6d6bb9-bd380a11}
De plus, les md5()
déclarations de fonction text
, vous pouvez utiliser decode()
pour convertir en bytea
et la représentation par défaut de c'est:
SELECT decode(md5('Store hash for long string, maybe for index?'), 'hex')
\220\267R^\204\366HP\302\357\264\007\372\343\362q
Il vous faudrait à encode()
nouveau pour obtenir la représentation textuelle originale:
SELECT encode(my_md5_as_bytea, 'hex');
Pour couronner le tout, les valeurs stockées bytea
occuperaient 20 octets en RAM (et 17 octets sur disque, 24 avec remplissage ) en raison de la surcharge internevarlena
, ce qui est particulièrement défavorable pour la taille et les performances des index simples.
Tout fonctionne en faveur d'un uuid
ici.
text
colonnes, même si ce n'est pas du tout un "texte".SELECT encode(decode('tZmffOd5Tbh8yXaVlZfRJQ==', 'base64'), 'hex')::uuid;
.uuid
est un type de 16 octets qui ne peut stocker les résultats d'aucun algorithme SHA produisant entre 160 et 512 bits. Aucun type similaire ne correspond à la distribution standard de Postgres. Vous pouvez en créer un ... À défautbytea
, comme le fait pg_crypto .Je voudrais stocker le MD5 dans un
text
ou unevarchar
colonne. Il n'y a pas de différence de performance entre les différents types de données de caractères. Vous voudrez peut-être limiter la longueur des valeurs md5 envarchar(xxx)
vous assurant que la valeur md5 ne dépasse jamais une certaine longueur.Les grandes listes IN ne sont généralement pas très rapides, il est préférable de faire quelque chose comme ceci:
Une autre option, parfois dite plus rapide, consiste à utiliser un tableau:
Comme vous ne faites que comparer pour l’égalité, un indice BTree normal devrait suffire. Les deux requêtes devraient pouvoir utiliser un tel index (surtout si elles ne sélectionnent qu'une petite fraction des lignes.
la source
bit
type, je ne peux donc rien en dire. Compte tenu du nombre de lignes que vous attendez, la suggestion d'Erwin semble être meilleure, car vous économisez de l'espace en enregistrant ceci sous le nom UUIDUne autre option consiste à utiliser 4 colonnes INTEGER ou 2 colonnes BIGINT.
la source