2010-08-11 6 views
3

Supposons que j'ai une table avec une colonne name varchar(20), et que je stocke une ligne avec name = "abcdef".Comment cela ne rend pas varchar2 inefficace?

INSERT INTO tab(id, name) values(12, 'abcdef'); 

Comment l'allocation de mémoire pour name fait dans ce cas?

Il y a deux façons que je peux penser:

a) est alloué, mais seulement 6 utilisés

20 octets. Dans ce cas varchar2 n'a pas d'avantage significatif sur char, en termes d'allocation de mémoire.

b)

Seuls six octets sont alloués. Si tel est le cas, et j'addded deux autres lignes après celui-ci,

INSERT INTO tab(id, name) values(13, 'yyyy'); 
INSERT INTO tab(id, name) values(14, 'zzzz'); 

puis je fais un UPDATE,

UPDATE tab SET name = 'abcdefghijkl' WHERE id = 12; 

Où le SGBD obtenir les 6 supplémentaires octets nécessaires de? Il peut y avoir un cas où les 6 octets suivants ne sont pas libres (si seulement 6 ont été alloués initialement, les octets suivants pourraient avoir été attribués pour quelque chose d'autre).

Existe-t-il un autre moyen que de déplacer la ligne vers un nouvel emplacement? Même le décalage serait un problème dans le cas de tables organisées en index (cela peut convenir aux tables organisées en tas).

+1

Cela dépend de l'implémentation, mais il est très probable que lorsque vous mettez à jour, la nouvelle ligne est écrite dans un endroit complètement différent de l'ancienne ligne. C'est vrai même sans varchar. – hobbs

Répondre

1

Il peut y avoir des variations en fonction des SGBDR que vous utilisez, mais en général:

Seules les données réelles que vous stockez dans un champ varchar est alloué. La taille est seulement un maximum autorisé, ce n'est pas combien est alloué.

Je pense que cela vaut aussi pour les champs char, sur certains systèmes. Les types de données de taille variable sont gérés de manière suffisamment efficace pour qu'il n'y ait plus aucun gain dans l'allocation du maximum. Si vous mettez à jour un enregistrement pour qu'il nécessite plus d'espace, l'enregistrement dans le même bloc d'allocation est déplacé vers le bas et si les enregistrements ne tiennent plus dans le bloc, un autre bloc est alloué et les enregistrements sont répartis entre les blocs . Cela signifie que les enregistrements sont continus dans les blocs d'allocation, mais que les blocs ne doivent pas être continus sur le disque.

+0

Sur les systèmes Oracle et DB2, un champ NOT NULL CHAR (n BYTES) consomme toujours n octets. –

1

Il n'alloue certainement pas plus d'espace que nécessaire, ce qui irait à l'encontre du point d'utilisation du type de longueur variable.

Dans le cas que vous mentionnez, je pense que les lignes ci-dessous doivent être déplacées vers le bas sur la page, peut-être que cela est optimisé d'une manière ou d'une autre. Je ne connais pas vraiment les détails exacts, peut-être que quelqu'un d'autre peut commenter davantage.

1

ModifierPour une raison quelconque, j'ai pensé que cela a été étiqueté Microsoft SQL Server. Je pense que la réponse est toujours pertinente si

Voilà pourquoi le official recommendation est

  • utilisez char lorsque les tailles des entrées de données de colonne sont cohérentes.
  • Utilisez varchar lorsque les tailles des entrées de données de colonne varient considérablement.
  • Utilisez varchar (max) lorsque les tailles des entrées de données de colonne varient considérablement, et que la taille peut dépasser 0,dépasser 8 000 octets.

Il est un compromis que vous devez considérer lors de la conception de votre structure de la table.Probablement, vous devrez tenir compte de la fréquence des mises à jour par rapport aux lectures dans ce calcul également

À noter que pour char une valeur NULL utilise toujours tout l'espace de stockage. Il existe un addin pour Management Studio appelé SQL Internals Viewer qui vous permet de voir facilement comment vos lignes sont stockées.

1

Cela dépend probablement fortement de la base de données. Quelques points cependant: MVCC les bases de données d'observation ne mettent pas réellement à jour les données sur le disque ou dans le cache mémoire. Ils insèrent une nouvelle ligne avec les données mises à jour et marquent l'ancienne ligne comme étant supprimée d'une certaine transaction. Après un moment, la ligne supprimée n'est visible pour aucune transaction et elle est récupérée.

Pour la question du stockage de l'espace, il est généralement sous la forme de 1-4 bytes of header + data (+ padding)

Dans le cas de caractères, les données sont rembourré pour atteindre la longueur suffisante. Dans le cas de varchar ou de texte, l'en-tête stocke la longueur des données qui suivent.

+0

Votre description du fonctionnement d'une base de données MVCC ne correspond pas à celle d'Oracle. Oracle mettra à jour la ligne en place, tout en écrivant des informations pour annuler la modification dans les deux segments de restauration ou annuler les tablespce afin que la version précédente puisse être lue. Ainsi que d'écrire dans le journal de rétablissement afin que le changement ne soit pas perdu en cas d'échec. –

1

Étant donné le VARCHAR2 dans le titre de la question, je suppose que votre question est centrée autour d'Oracle. Dans Oracle, vous pouvez réserver de l'espace pour l'expansion de lignes dans un bloc de données à l'aide de la clause PCTFREE. Cela peut aider à atténuer les effets des mises à jour rendant les lignes plus longues. Cependant, si Oracle n'a pas assez d'espace libre dans le bloc pour réécrire la ligne, ce qu'il fait est appelé migration de ligne; il laisse l'adresse d'origine sur le disque seul (il n'a donc pas nécessairement besoin de mettre à jour les index), mais au lieu de stocker les données dans l'emplacement d'origine, il stocke un pointeur sur la nouvelle adresse de cette ligne. Cela peut entraîner des problèmes de performances dans les cas où une table est fortement accédée par des index si un nombre significatif de lignes a migré, car elle ajoute des E/S supplémentaires pour satisfaire les requêtes.