Разреженные данные:эффективное хранение и извлечение данных в RDBMS
-
03-07-2019 - |
Вопрос
У меня есть таблица, представляющая значения показателей исходного файла по редакциям проекта, например, следующим образом:
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
(Реляционное представление приведенных выше данных отличается.Каждая строка содержит следующие столбцы:Редакция, идентификатор файла, Значение.Файлы и их редакции, из которых вычисляются данные, хранятся в репозиториях Subversion, поэтому мы пытаемся представить структуру репозитория в виде реляционной схемы.)
В 10000 ревизиях может быть до 23750 файлов (это относится к Магия изображений программа рисования).Как вы можете видеть, большинство значений одинаковы между последовательными ревизиями, поэтому полезных данных в таблице довольно мало.Я ищу способ хранения данных, которые
- позволяет избежать репликации и эффективно использует пространство (в настоящее время для разреженного представления требуется 260 ГБ (данные + индекс) для менее чем 10% данных, которые я хочу сохранить).
- позволяет мне эффективно извлекать значения для конкретной ревизии с помощью SQL-запроса (без явного перебора ревизий или файлов)
- позволяет мне эффективно извлекать ревизию для определенного значения показателя.
В идеале решение не должно зависеть от конкретного СУБД и должен быть совместим с Впадать в спящий режим.Если это невозможно, я могу смириться с использованием функций, специфичных для Hibernate, MySQL или PostgreSQL.
Решение
Вот как я мог бы это смоделировать.Я опустил таблицу ревизий и таблицу файлов, поскольку они должны быть понятны сами по себе.
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
Чтобы получить все значения для файлов определенной ревизии, вы могли бы использовать следующий запрос.Присоединение к таблице files с помощью внешнего соединения позволит вам получить те файлы, которые не имеют определенного значения для этой ревизии.
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
Предполагая, что я правильно понимаю, чего вы хотите в своем третьем пункте, это позволит вам получить все ревизии, для которых конкретный файл имеет определенное значение:
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