• Aucun résultat trouvé

9.2 Fichiers

9.2.1 Enregistrements

Pour le système d’exploitation, un fichier est une suite d’octets répartis sur un ou plusieurs blocs. Les fichiers gérés par un SGBD sont un peu plus structurés. Ils sont constitués d’enregistrements (records en anglais) qui représentent physiquement les!! entités"" du SGBD. Selon le modèle logique du SGBD, ces entités peuvent être des n-uplets dans une relation, ou des objets. Nous nous limiterons au premier cas dans ce qui suit.

Un n-uplet dans une table relationnelle est constitué d’une liste d’attributs, chacun ayant un type. À ce n-uplet correspond un enregistrement, constitué de champs (field en anglais). Chaque type d’attribut détermine la taillle du champ nécessaire pour stocker une instance du type. Le tableau 9.3 donne la taille habituelle utilisée pour les principaux types de la norme SQL, étant entendu que les systèmes sont libres de choisir le mode de stockage.

Type Taille en octets SMALLINT 2 INTEGER 4 BIGINT 8 FLOAT 4 DOUBLE PRECISION 8 NUMERIC(M,D) M, (D+2 siM m D) DECIMAL(M,D) M, (D+2 siM m D) CHAR(M) M VARCHAR(M) L+1avecLn M BIT VARYING m H * DATE 8 TIME 6 DATETIME 14

TAB. 9.3 – Types SQL et tailles (en octets)

La taille d’un n-uplet est, en première approximation, la somme des tailles des champs stockant ses attributs. En pratique les choses sont un peu plus compliquées. Les champs – et donc les enregistrements – peuvent être de taille variable par exemple. Si la taille de l’un de ces enregistrements de taille variable, augmente au cours d’une mise à jour, il faut pouvoir trouver un espace libre. Se pose également la question de la représentation des valeursNULL. Nous discutons des principaux aspects de la représentation des enregistrements dans ce qui suit.

Champs de tailles fixe et variable

Comme l’indique le tableau 9.3, les types de la norme SQL peuvent être divisés en deux catégories : ceux qui peuvent être représentés par un champ une taille fixe, et ceux qui sont représentés par un champ de taille variable.

Les types numériques (entiers et flottants) sont stockés au format binaire sur 2, 4 ou 8 octets. Quand on utilise un typeDECIMALpour fixer la précision, les nombres sont en revanche stockés sous la forme d’une chaîne de caractères. Par exemple un champ de typeDECIMAL(12,2)sera stocké sur 12 octets, les deux derniers correspondant aux deux décimales. Chaque octet contient un caractère représentant un chiffre.

Les typesDATEetTIMEpeuvent être simplement représentés sous la forme de chaînes de caractères, aux formats respectifs ’AAAAMMJJ’ et ’HHMMSS’.

Le typeCHARest particulier : il indique une chaîne de taille fixe, et unCHAR(5)sera donc stocké sur 5 octets. Se pose alors la question : comment est représentée la valeur ’Bou’ ? Il y a deux solutions :

– on complète les deux derniers caractères avec des blancs ;

– on complète les deux derniers caractères avec un caractère conventionnel.

La convention adoptée influe sur les comparaisons puisque dans un cas on a stocké ’Bou ’ (avec deux blancs), et dans l’autre ’Bou’ sans caractères de terminaison. Si on utilise le typeCHARil est important d’étudier la convention adoptée par le SGBD.

On utilise beaucoup plus souvent le typeVARCHAR(n)qui permet de stocker des chaînes de longueur variable. Il existe (au moins) deux possibilités :

– le champ est de longueurc

]

$ , le premier octet contenant un entier indiquant la longueur exacte de la chaîne ; si on stocke ’Bou’ dans unVARCHAR(10), on aura donc ’3Bou’, le premier octet stockant un 3 au format binaire, les trois octets suivants des caratères ’B’, ’o’ et ’u’, et les 7 octets suivants restant inutilisés ;

– le champ est de longueuro

]

$ , aveco=mpc ; ici on ne stocke pas les octets inutilisés, ce qui permet d’économiser de l’espace.

Noter qu’en représentant un entier sur un octet, on limite la taille maximale d’unVARCHARà 255. Une variante qui peut lever cette limite consiste à remplacer l’octet initial contenant la taille par un caractère de terminaison de la chaîne (comme en C).

Le typeBIT VARYINGpeut être représenté comme unVARCHAR, mais comme linformation stockée ne contient pas que des caractères codés en ASCII, on ne peut pas utiliser de caractère de terminaison puisqu’on ne saurait par le distinguer des caractères de la valeur stockée. On préfixe donc le champ par la taille utile, sur 2, 4 ou 8 octets selon la taille maximale autorisé pour ce type.

On peut utiliser un stockage optimisé dans le cas d’un type énuméré dont les instances ne peuvent prendre leur (unique) valeur que dans un ensemble explicitement spécifié (par exemple avec une clause CHECK). Prenons l’exemple de l’ensemble de valeurs suivant :

{’valeur1’,’valeur2’, ...’valeurN’}

Le SGBD doit contrôler, au moment de l’affectation d’une valeur à un attribut de ce type, qu’elle ap- partient bien à l’ensemble énuméré {’valeur1’,’valeur2’, ...’valeurN’}. On peut alors stocker l’indice de la valeur, sur 1 ou 2 octets selon la taille de l’ensemble énuméré (au maximum 65535 valeurs pour 2 octets). Cela représente un gain d’espace, notamment si les valeurs consistent en chaînes de carac- tères.

En-tête d’enregistrement

De même que l’on préfixe un champ de longueur variable par sa taille utile, il est souvent nécessaire de stocker quelques informations complémentaires sur un enregistrement dans un en-tête. Ces informations peuvent être ;

– la taille de l’enregistrement, s’il est de taille variable ;

– un pointeur vers le schéma de la table, pour savoir quel est le type de l’enregistrement ; – la date de dernière mise à jour ;

– etc

On peut également utiliser cet en-tête pour les valeursNULL. L’absence de valeur pour un des attributs est en effet délicate à gérer : si on ne stocke rien, on risque de perturber le découpage du champ, tandis que si on stocke une valeur conventionnelle, on perd de l’espace. Une solution possible consiste à créer un masque de bits, un pour chaque champ de l’enregistrement, et à donner à chaque bit la valeur 0 si le champ estNULL, et 1 sinon. Ce masque peut être stocké dans l’en-tête de l’enregistrement, et on peut alors se permettre de ne pas utiliser d’espace pour une valeurNULL, tout en restant en mesure de décoder correctement la chaîne d’octets constituant l’enregistrement.

Exemple 9.3 Prenons l’exemple d’une table Film avec les attributs id de type INTEGER,titrede

typeVARCHAR(50)etanneede typeINTEGER. Regardons la représentation de l’enregistrement (123, ’Vertigo’, NULL) (donc l’année est inconnue).

L’identifiant est stocké sur 4 octets, et le titre sur 8 octets, dont un pour la longueur. L’en-tête de l’enregistrement contient un pointeur vers le schéma de la table, sa longueur totale (soit 4 + 8), et un masque de bits 110 indiquant que le troisième champ est àNULL. La figure 9.6 montre cet enregistrement : notez qu’en lisant l’en-tête, on sait calculer l’adresse de l’enregistrement suivant.

j