Dados esparsos: armazenamento e recuperação eficientes em um RDBMS
-
03-07-2019 - |
Pergunta
Eu tenho uma tabela representando valores das métricas de arquivo de origem nas revisões do projeto, como as seguintes:
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
(A visão relacional dos dados acima é diferente. Cada linha contém as seguintes colunas: revisão, fileID, valor. Os arquivos e suas revisões a partir das quais os dados são calculados são armazenados em repositórios de subversão, por isso estamos tentando representar o repositório do repositório estrutura em um esquema relacional.)
Pode haver até 23750 arquivos em 10000 revisões (este é o caso do Imagemagick programa de desenho). Como você pode ver, a maioria dos valores é a mesma entre revisões sucessivas; portanto, os dados úteis da tabela são bastante escassos. Estou procurando uma maneira de armazenar os dados que
- Evita a replicação e usa o espaço com eficiência (atualmente a representação não escolar requer 260 GB (dados+índice) por menos de 10% dos dados que desejo armazenar)
- Permite -me recuperar com eficiência os valores para uma revisão específica usando uma consulta SQL (sem explicitamente percorrer revisões ou arquivos)
- Permite -me recuperar com eficiência a revisão para um valor métrico específico.
Idealmente, a solução não deve depender de um determinado Rdbms e deve ser compatível com Hibernate. Se isso não for possível, posso viver usando recursos de hibernação, mysql ou postgreSQL.
Solução
É assim que posso modelá -lo. Deixei de fora a tabela de revisões e a tabela de arquivos, pois eles devem ser bastante auto-explicativos.
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
Para obter todos os valores para arquivos de uma revisão específica, você pode usar a seguinte consulta. Entrar na tabela de arquivos com uma junção externa permitiria que você obtenha aqueles que não têm valor definido para essa revisão.
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
Supondo que eu entendi corretamente o que você deseja no seu terceiro ponto, isso permitirá que você obtenha todas as revisões para as quais um arquivo específico tem um determinado valor:
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