Données éparses: stockage et extraction efficaces dans un SGBDR
-
03-07-2019 - |
Question
J'ai un tableau représentant les valeurs des métriques du fichier source pour toutes les révisions du projet, comme suit:
Revision FileA FileB FileC FileD FileE ...
1 45 3 12 123 124
2 45 3 12 123 124
3 45 3 12 123 124
4 48 3 12 123 124
5 48 3 12 123 124
6 48 3 12 123 124
7 48 15 12 123 124
(La vue relationnelle des données ci-dessus est différente. Chaque ligne contient les colonnes suivantes: Révision, FileId, Valeur. Les fichiers et leurs révisions à partir desquels les données sont calculées sont stockés dans des référentiels Subversion, nous essayons de représente la structure du référentiel dans un schéma relationnel.)
Il peut y avoir jusqu'à 23750 fichiers dans 10 000 révisions (c'est le cas de la ImageMagick programme de dessin). Comme vous pouvez le constater, la plupart des valeurs sont identiques entre les révisions successives, de sorte que les données utiles de la table sont relativement rares. Je cherche un moyen de stocker les données qui
- évite la réplication et utilise efficacement l'espace (actuellement, la représentation non fragmentée nécessite 260 Go (données + index) pour moins de 10% des données que je souhaite stocker.
- me permet de récupérer efficacement les valeurs d'une révision spécifique à l'aide d'une requête SQL (sans effectuer explicitement une boucle dans les révisions ou les fichiers)
- me permet de récupérer efficacement la révision pour une valeur de mesure spécifique.
Idéalement, la solution ne devrait pas dépendre d'un SGBDR particulier et devrait être compatible avec < a href = "http://en.wikipedia.org/wiki/Hibernate_%28Java%29" rel = "nofollow noreferrer"> Hibernate . Si cela n’est pas possible, je peux utiliser les fonctionnalités spécifiques à Hibernate, MySQL ou PostgreSQL.
La solution
Voici comment je pourrais le modéliser. J'ai laissé de côté le tableau des révisions et le tableau des fichiers, car ceux-ci devraient être assez explicites.
CREATE TABLE Revision_Files
(
start_revision_number INT NOT NULL,
end_revision_number INT NOT NULL,
file_number INT NOT NULL,
value INT NOT NULL,
CONSTRAINT PK_Revision_Files PRIMARY KEY CLUSTERED (start_revision_number, file_number),
CONSTRAINT CHK_Revision_Files_start_before_end CHECK (start_revision_number <= end_revision_number)
)
GO
Pour obtenir toutes les valeurs des fichiers d’une révision particulière, vous pouvez utiliser la requête suivante. La jonction à la table des fichiers avec une jointure externe vous permet d’obtenir ceux qui n’ont pas de valeur définie pour cette révision.
SELECT
REV.revision_number,
RF.file_number,
RF.value
FROM
Revisions REV
INNER JOIN Revision_Files RF ON
RF.start_revision_number <= REV.revision_number AND
RF.end_revision_number >= REV.revision_number
GO
En supposant que je comprenne bien ce que vous voulez dans votre troisième point, cela vous permettra d'obtenir toutes les révisions pour lesquelles un fichier particulier a une certaine valeur:
SELECT
REV.revision_number
FROM
Revision_Files RF
INNER JOIN Revisions REV ON
REV.revision_number BETWEEN RF.start_revision_number AND RF.end_revision_number
WHERE
RF.file_number = @file_number AND
RF.value = @value
GO