web-dev-qa-db-fra.com

Dois-je utiliser Enum quand il y a trop de "catégories" avec PostgreSQL?

Problème

Je prévois de charger un CSV avec plus de 10 millions d'enregistrements dans PostgreSQL V12.1, l'une de ses colonnes a des valeurs "catégoriques", ce qui crée un type énuméré pour cela semble être un bon choix, mais il détient 208 catégories.

Le champ le plus court a 2 ans et le plus long est de 11 caractères. La moyenne de tous les champs est de 2,4. Le codage du personnage est UTF8, mais tous les caractères sont ASCII .

Des questions:

Quel type dois-je utiliser énuméré ou varchar ?

Information additionnelle

Je jette Char parce que la documentation officielle PostgreSQL - états le fichier suivant Char , varchar et texte :

CONSEIL: Il n'y a pas de différence de performance parmi ces trois types, en dehors de l'augmentation de l'espace de stockage lorsque vous utilisez le type rembourré en blanc et quelques cycles de processeur supplémentaires pour vérifier la longueur lors de la mémorisation d'une colonne à contrainte de longueur. Alors que le caractère (N) a des avantages de performance dans certains autres systèmes de base de données, il n'existe aucun avantage de ce type dans PostgreSQL; En fait, le caractère (n) est généralement le plus lent des trois en raison de ses coûts de stockage supplémentaires. Dans la plupart des situations, le texte ou le caractère variables devraient être utilisés à la place.

Un Enum La valeur dans PostgreSQL occupe 4 octets sur le disque (voir 8.7.4. Détails de la mise en œuvre). Considérant que cette longueur de chaîne moyenne et 2,4 à l'aide du type ENUM conduirait une utilisation légèrement supérieure à un disque (Scorches courtes dans PostgreSQL a besoin d'un espace de disque d'octet supplémentaire). J'ai toujours l'intention que l'utilisation de Enum est un meilleur choix, car sa mise en œuvre rend de nombreuses opérations plus rapidement contre elle.

5
atevm

Avec une moyenne de 2,4 caractères (plus pertinent: avg octets - Mais c'est la même chose pour tous ASCII caractères), je n'aurais pas la peine d'utiliser Enums. Ceux-ci occupent 4 octets sur le disque plus, éventuellement, un rembourrage d'alignement. (text ne nécessite pas de rembourrage d'alignement.) Vous n'abandonnez même pas de stockage et obtenez plus de frais généraux pour cela.

Avec la plupart des valeurs inférieures à 7 caractères (= 8 octets sur disque), un index sur une colonne de catégorie text sera également légèrement plus grand qu'un sur un enum. (L'espace pour les données est (généralement) attribué en multiples de 8 octets.)

Pour un nombre fixe de 208 catégories, un "char" Encodage (ne pas être confondu avec char!) Peut-être une option pour enregistrer le stockage. Voir:

Mais encore une fois, ne vaut pas la peine pour de telles petites chaînes. Il suffit d'utiliser text. Peut-être appliquer l'exactitude avec une contrainte FK à une table category comme:

CREATE TABLE category (category text PRIMARY KEY);

Aussi un bon endroit pour stocker des informations supplémentaires par catégorie. Et vous pouvez facilement modifier l'ensemble des catégories. Faire la contrainte FK ON UPDATE CASCADE Et vous pouvez changer de nom de catégorie dans un endroit central. Fais-le ON DELETE SET NULL, et vous pouvez facilement supprimer une catégorie. Etc.

En rapport:

6
Erwin Brandstetter

Je supporte pleinement la réponse d'Erwin, mais je voulais ajouter un avertissement contre Enums.

Enums sont un bon choix si vous avez un nombre fixe de valeurs possibles qui ne peuvent jamais changer (au moins, il doit y avoir une garantie qu'aucune valeur ne devrait être supprimée).

Dans tous les autres cas, vous ne devez pas utiliser Enums: Il est impossible de supprimer une valeur d'énorme une fois que vous l'avez ajoutée.

Par exemple, lors du choix d'un type de données pour une colonne contenant un état américain, je voudrais pas Choisissez une insuffisance - improbable telle qu'elle est, il pourrait s'agir d'un état sécable, ou de deux états unir.

Sur la base de la façon dont vous décrivez les données, je ne recommanderais pas Enums dans votre cas.

2
Laurenz Albe