La recherche d'index serait-elle sensiblement plus rapide avec char vs varchar lorsque toutes les valeurs sont de 36 caractères

30

J'ai un schéma hérité (avertissement!) Qui utilise un identifiant généré par hachage pour la clé primaire de toutes les tables (il y en a beaucoup). Un exemple d'un tel identifiant est:

922475bb-ad93-43ee-9487-d2671b886479

Il n'y a aucun espoir possible de changer cette approche, mais les performances avec l'accès à l'index sont médiocres. Abstraction faite de la myriade de raisons , cela pourrait être, il y a une chose que j'ai remarqué qui semblait moins optimale - malgré toutes les valeurs id dans toutes les nombreuses tables étant exactement 36 caractères, le type de colonne est varchar(36), non char(36) .

La modification des types de colonnes à longueur fixe char(36)offrirait-elle des avantages significatifs en termes de performances d'index, au-delà de la très faible augmentation du nombre d'entrées par page d'index, etc.?

C'est-à-dire que les postgres fonctionnent beaucoup plus rapidement lorsqu'il s'agit de types de longueur fixe que de types de longueur variable?

Veuillez ne pas mentionner l'économie de stockage minuscule - cela n'aura pas d'importance par rapport à la chirurgie nécessaire pour effectuer la modification des colonnes.

bohémien
la source

Réponses:

40

Non, pas de gain du tout . Le manuel indique explicitement :

Conseil: Il n'y a pas de différence de performances entre ces trois types , à part un espace de stockage accru lors de l'utilisation du type à remplissage vierge et quelques cycles CPU supplémentaires pour vérifier la longueur lors du stockage dans une colonne à longueur limitée. Bien qu'il character(n)présente des avantages en termes de performances dans certains autres systèmes de base de données, il n'y en a pas dans PostgreSQL; en fait, character(n)c'est généralement le plus lent des trois en raison de ses coûts de stockage supplémentaires. Dans la plupart des situations text ou character varyingdevrait être utilisé à la place .

Gras accent mien.

char(n)est un type largement obsolète et inutile. Restez avec varchar(n). Si vous n'avez pas besoin d'appliquer la longueur, varcharou textsi vous seriez un peu plus rapide. Vous ne pourrez pas mesurer une différence.

De plus, si toutes les chaînes ont exactement 36 caractères, il n'y a aucune sauvegarde de stockage dans les deux sens, même pas minuscule. Les deux ont exactement la même taille sur le disque et dans la RAM. Vous pouvez tester avec pg_column_size()(sur une expression et sur une colonne de table).

En relation:

Vous n'avez pas demandé d' autres options , mais j'en mentionnerai deux:

  1. COLLATION- sauf si vous exécutez votre base de données avec le classement "C" . L'assemblage est souvent négligé et peut-être coûteux. Étant donné que vos chaînes ne semblent pas avoir de sens dans un langage naturel, il est probablement inutile de suivre les COLLATIONrègles. En relation:

    Benchmark étendu comparant (entre autres) l'effet de COLLATE "C"sur les performances:

  2. UUID , évidemment. Votre chaîne ressemble étrangement à un UUID (32 chiffres hexadécimaux plus 4 délimiteurs). Il serait beaucoup plus efficace de les stocker en tant queuuidtype de donnéesréel, ce qui est plus rapide de plusieurs façons et n'occupe que 16 octets - contre 37 octets en RAM pourchar(36)ouvarchar(36)(oustocké sans délimiteurs, juste les 32 caractères définissant), ou 33 octets sur le disque. Mais le remplissage de l'alignement entraînerait 40 octets dans les deux cas dans de nombreux cas.)COLLATIONSerait également non pertinent pour leuuidtype de données.

    SELECT '922475bb-ad93-43ee-9487-d2671b886479'::uuid

    Cela peut être utile (derniers chapitres):

    Voir également:

Erwin Brandstetter
la source
cela signifie-t-il qu'un caractère / varchar (n) de longueur limitée passera des cycles CPU à vérifier la contrainte tandis que le champ de texte de longueur variable stockera le texte séparément de manière moins accessible par rapport au caractère, qui gagne dans ce scénario et est ce gagnant vaut même la peine d'envisager, disons, 10 millions de lignes avec un morceau de texte
PirateApp
1
@PirateApp: ne gagne char(n)presque jamais en aucune façon. Ne l'utilisez pas. Les types de données textet varchar(sans modificateur de longueur) sont compatibles binaires et partagent les mêmes caractéristiques de performances. Il y a des raisons historiques pour que les deux coexistent à Postgres. En interne, textest le type "préféré" parmi les types de chaîne (qui peut influencer la résolution du type de fonction). Les cycles du processeur pour appliquer à varchar(n)peine la matière. Utilisez une restriction de longueur lorsque vous en avez besoin . Dans le cas présent, uuidc'est le vrai gagnant.
Erwin Brandstetter