Dans le premier article sur la structure du fichier QVD, j'ai décrit la structure générale et m'attarder sur les métadonnées de manière suffisamment détaillée. Dans cet article, je vais décrire le format de stockage des informations sur les colonnes et partager mon expérience dans l'interprétation de ces données.
Donc (rappelez-vous) un fichier QVD correspond à une table relationnelle, qui, comme vous le savez, se compose de lignes. Chaque ligne de la table, à son tour, se compose de colonnes (ou champs), et les lignes ont la même structure, qui peut être décrite, par exemple, par l'opérateur SQL (créer une table).
Dans un fichier QVD, une table est stockée en deux parties liées indirectement:
Les tables de caractères (mon terme) contiennent des valeurs uniques pour chaque colonne de la table source. C'est à leur sujet que nous discuterons ci-dessous.
La table de lignes contient les lignes de la table source, chaque ligne stocke les indices des valeurs de colonne (champ) de la ligne dans la table de symboles correspondante. Je vais discuter du tableau des lignes plus en détail dans la troisième partie de cette série.
Sur l'exemple de notre assiette (rappelez-vous - de la première partie)
SET NULLINTERPRET =<sym>; tab1: LOAD * INLINE [ ID, NAME 123.12,"Pete" 124,12/31/2018 -2,"Vasya" 1,"John" <sym>,"None" ];
Dans cette assiette:
- 5 lignes
- le champ "ID" a 4 valeurs uniques (NULL n'est pas considéré comme une valeur, plus en détail à ce sujet dans la troisième partie)
- le champ "NAME" a 5 valeurs uniques
- la première ligne du tableau des lignes contiendra les index 0 et 0, correspondant respectivement aux valeurs 123.12 et «Pete»
Occasions spéciales
En règle générale, des tables de symboles sont créées pour tous les champs de table du fichier QVD. Mais il y a des nuances.
Si le champ a une valeur, cette valeur est généralement stockée dans la table des symboles (dans ce cas, la table des symboles contiendra un enregistrement). Et dans le tableau des lignes, le champ sera absent (car il est donc clair quelle devrait être la valeur de ce champ dans chaque ligne ...)
Si le champ n'a aucune valeur (contient toujours NULL), aucune table de symboles n'est créée dessus.
Ces cas particuliers seront décrits dans la troisième partie, lorsque nous arriverons aux lignes et à l'algorithme pour leur recréation.
Stockage des tables de caractères dans un fichier
Chaque table de symboles est stockée dans un fichier QVD sous forme de bloc binaire, son décalage (par rapport au début du bloc binaire) est contenu dans le champ Décalage de la section de métadonnées de ce champ, la longueur (en octets) est dans le champ Longueur des métadonnées.
Ainsi, la première table de caractères aura toujours un décalage de 0.
Les tables de symboles se succèdent et ne sont en aucun cas séparées les unes des autres.
Structure de la table des caractères
La table des symboles contient des valeurs de champ qui se succèdent sans séparateurs, chaque valeur est représentée comme suit:
- un octet code le type de champ (je décrirai ci-dessous)
- vient ensuite la valeur binaire facultative (dépend du type de champ)
- suivi d'une valeur de chaîne facultative (dépend du type de champ)
Les chaînes sont stockées «telles quelles» (dans l'encodage spécifié dans les métadonnées), la chaîne se termine par un octet zéro. La chaîne peut avoir une longueur nulle, c'est-à-dire se composent de zéro octet uniquement.
Les valeurs binaires sont stockées selon les règles de l'architecture où le fichier QVD a été généré (d'après mon expérience, vous pouvez simplement les lire sous forme de valeurs binaires avec un œil sur "endian").
Types de champs
Toute la variété des types de données QVD réunis avec trois bases
- (1) entier (4 octets)
- (2) virgule flottante (8 octets)
- (4) ligne se terminant par zéro
Il existe également des types combinés
- (5) un entier suivi de sa représentation sous forme de chaîne (4 octets plus une chaîne avec un octet zéro)
- (6) un nombre à virgule flottante suivi de sa représentation sous forme de chaîne (8 octets plus une chaîne avec un octet zéro)
Entre parenthèses, j'ai donné les valeurs numériques des «types» (le premier octet de la valeur du champ dans la table des symboles).
Un esprit curieux demandera: "Où sont les trois?" Ce n'est pas pour moi, j'ai aussi beaucoup de questions, des commentaires ici, comme l'a dit le héros de Khabensky dans le célèbre film "Je m'abstiendrai ..."
En général, c'est tout, ce n'est pas difficile - non?
Deux observations pratiques peu agréables
Un même champ peut avoir des valeurs de différents types dans la table des symboles (entier, flottant et chaînes). Je n'y ai pas cru moi-même avant d'avoir mené une série d'expériences ... La seule chose qui puisse être "garantie" (avec la mise en garde de la première partie - rien ne peut être garanti) - il ne peut y avoir de mélange de "nombre" et de "numéro avec une chaîne" (l'un ou l'autre) ) C'est important, un esprit curieux comprendra :-).
Les valeurs des champs non numériques (pas les types 1 et 2 dans la notation ci-dessus) doivent être lues dans une rangée - il est impossible de se positionner sur le champ numéro N ... C'est compréhensible, mais inefficace (en termes de traitement).
Considérez à nouveau notre étiquette ci-dessus, la table des caractères du champ ID ressemblera à ceci (j'écris octet / caractère):
- nombre 6 (type) + 8 octets (valeur flottante 123.12) + 7 octets (chaîne "123.12" avec zéro octet)
- nombre 5 (type) + 4 octets (valeur entière 124) + 4 octets (chaîne "124" avec zéro octet)
- nombre 5 (type) + 4 octets (entier -2) + 3 octets (chaîne "-2" avec zéro octet)
- nombre 5 (type) + 4 octets (entier 1) + 2 octets (chaîne "1" avec zéro octet)
Un total de 40 octets (voir la partie précédente - métadonnées, la valeur de l'attribut Longueur pour le champ ID).
De la pratique
La tâche pratique (l'une des), comme je l'ai déjà écrit, était pour moi de recréer la table à l'aide du fichier QVD. D'après ce qui précède, il résulte (au moins - cela devrait suivre, j'ai essayé :-)) qu'à partir de la description de la colonne (métadonnées plus données), il est impossible de déterminer sans ambiguïté le type de champ (celui qui, par exemple, écrit dans le "tableau de création ...") .
Comme je l'ai mentionné dans la première partie - 90% des champs ont un type INCONNU dans les métadonnées, les balises ne vous permettent pas non plus de définir de manière unique le type de champ (je ne chargerai pas le lecteur avec les détails - croyez-moi) ...
Comment être
Dans mon travail, j'ai suivi le chemin statistique - j'analyse un certain pourcentage des valeurs des colonnes et, à partir des résultats, je tire une conclusion - quel type lui attribuer. La précision est tout à fait satisfaisante, le problème est que vous devez analyser (dans le cas général) toutes les données ... Dans ma pratique, je me suis limité aux 5-10% des valeurs de champ.
Si nous terminons par les types de données, un esprit interrogateur posera une question raisonnable - la «création de table» mentionnée implique beaucoup plus de types de données ...
Je dirai ceci: dans les fichiers traités, aucun type de données autre que ceux énumérés ci-dessus n'a été trouvé. Les fichiers correspondaient à des tables très réelles de vraies bases de données et contenaient tout le spectre des types de données (par exemple, j'ai même eu des blobs ... Pourquoi sont-ils dans QVD ??? Il serait préférable d'écrire des commentaires).
Probablement, pour compléter l'image avec les types de données, vous devez expliquer les dates et les horodatages (les autres types sont une question de longueur).
Les dates sont présentées dans QVD sous la forme d'un entier - le nombre de jours depuis le début de l'ère (cliquez sur l'ère). Les experts de QlikView / QlikSense vous indiqueront facilement quand cela a commencé (même si c'était le 30 décembre 1899, ne demandez pas pourquoi).
Les horodatages dans QVD sont représentés par un nombre à virgule flottante contenant la date comme décrit ci-dessus et l'heure dans la partie fractionnaire (où .0 correspond à l'heure "00:00:00" et .999999 correspond à l'heure "23:59:59" - voir plus en détail, par exemple ici ).
Je n'ai pas encore creusé dans cette direction - mes tables recréées à partir de QVD contiennent des types entiers et flottants pour des champs comme "date" et "datetime". Vous pouvez également utiliser la représentation sous forme de chaîne - pour les champs de ce type, une représentation combinée est toujours utilisée (types 5 et 6).
Le dernier (sur la pratique) - lors de la lecture de fichiers volumineux, il est logique de créer des index pour les champs de chaîne, ce que j'ai fait. Cela réduit considérablement le temps de traitement dans les cas où la taille de la table des symboles est bien inférieure au nombre de lignes (c'est-à-dire qu'une valeur apparaît plus d'une fois dans le champ de la table d'origine).
Pour résumer
Dans cet article, nous avons examiné le stockage des valeurs uniques des champs (colonnes), vu que les colonnes sont stockées sous la forme d'une séquence de valeurs uniques, réalisé que les types de données sont mélangés et qu'il n'y a que trois types (entier, flottant et ligne).
Ensuite, nous devons nous familiariser avec le stockage des chaînes - la troisième et dernière partie d'une série d'articles sur la structure QVD y sera consacrée.