PostgreSQL bytea против smallint []

9

Я хочу импортировать большие (100 МБ - 1 ГБ) данные многоканальных временных рядов в базу данных PostgreSQL. Данные поступают из файлов формата EDF, которые разделяют данные на «записи» или «эпохи», обычно по несколько секунд каждый. Запись каждой эпохи содержит сигналы для каждого канала данных в виде последовательных массивов коротких целых чисел.

Я уполномочен хранить файлы в базе данных, в худшем случае как BLOB. Учитывая это, я хотел бы изучить варианты, которые позволили бы мне сделать что-то большее с данными в базе данных, например, облегчить запросы, основанные на данных сигнала.

Мой первоначальный план - хранить данные в виде одной строки на запись эпохи. Я пытаюсь взвесить, сохранять ли фактические данные сигнала в виде байтов или smallint [] (или даже smallint [] []). Может ли кто-нибудь рекомендовать один над другим? Я заинтересован в хранении и стоимости доступа. Использование может быть вставлено один раз, время от времени читать, никогда не обновлять. Если бы его было легче обернуть как пользовательский тип, чтобы я мог добавить функции для анализа сравнения записей, то тем лучше.

Без сомнения, у меня мало деталей, поэтому не стесняйтесь добавлять комментарии к тому, что вы хотите, чтобы я разъяснил.

beldaz
источник
2
Это может быть одним из немногих разумных способов использования массива в модели авторских данных, поскольку вы экономите много места на диске, избегая затрат на строки длиной от 24 до 28 байт. Массивы также сжимаются и сохраняются вне строки, если это достаточно долго.
Крейг Рингер
Beldaz, способ, которым вы должны хранить данные, во многом зависит от того, как вы планируете получить к ним доступ и как часто. Если данные редко запрашиваются, и вы всегда хотите просто извлекать данные для каждой записи, я думаю, что одна строка на запись в массиве имеет смысл. Однако, если вы хотите выполнить какие-либо запросы, которые являются немного более глубокими, например, например, вытащить все записи для данного пациента_идентификатора, то, возможно, мы можем предложить небольшое улучшение структуры хранения. Любые идеи о ваших шаблонах запросов?
Крис
@ Крис Спасибо. Я упустил компонент метаданных, так как он очень маленький и может находиться в отдельном отношении. Шаблоны запросов не определены, но я могу сравнить два разных файла, записанных одновременно, и извлечь сигналы из одновременных эпох.
бельдаз
@CraigRinger Я не видел много доказательств сжатия массива. Это нужно как-то включить?
Белдаз

Ответы:

11

В отсутствие каких-либо ответов я сам изучил проблему.

Похоже, что пользовательские функции могут обрабатывать все базовые типы, включая bytea и smallint[], так что это не сильно влияет на выбор представления.

Я опробовал несколько различных представлений на сервере PostgreSQL 9.4, работающем локально на ноутбуке с Windows 7 с ванильной конфигурацией. Отношения для хранения этих фактических данных сигнала были следующими.

Большой объект для всего файла

CREATE TABLE BlobFile (
    eeg_id INTEGER PRIMARY KEY,
    eeg_oid OID NOT NULL
);

SMALLINT массив на канал

CREATE TABLE EpochChannelArray (
    eeg_id INT NOT NULL,
    epoch INT NOT NULL,
    channel INT,
    signal SMALLINT[] NOT NULL,
    PRIMARY KEY (eeg_id, epoch, channel)
);

BYTEA за канал в каждую эпоху

CREATE TABLE EpochChannelBytea (
    eeg_id INT NOT NULL,
    epoch INT NOT NULL,
    channel INT,
    signal BYTEA NOT NULL,
    PRIMARY KEY (eeg_id, epoch, channel)
);

SMALLINT 2D массив за эпоху

CREATE TABLE EpochArray (
    eeg_id INT NOT NULL,
    epoch INT NOT NULL,
    signals SMALLINT[][] NOT NULL,
    PRIMARY KEY (eeg_id, epoch)
);

Массив BYTEA за эпоху

CREATE TABLE EpochBytea (
    eeg_id INT NOT NULL,
    epoch INT NOT NULL,
    signals BYTEA NOT NULL,
    PRIMARY KEY (eeg_id, epoch)
);

Затем я импортировал выборку файлов EDF в каждое из этих отношений через Java JDBC и сравнивал рост размера базы данных после каждой загрузки.

Файлы были:

  • Файл A: 2706 эпох из 16 каналов, каждый канал 1024 выборки (16385 выборок в эпоху), 85 МБ
  • Файл B: 11897 эпох из 18 каналов, каждый канал 1024 выборки (18432 выборки в эпоху), 418 МБ
  • Файл C: 11746 эпох из 20 каналов, каждый канал от 64 до 1024 выборок (17088 выборок за эпоху), 382 МБ

С точки зрения стоимости хранения, вот размер, занимаемый в МБ для каждого случая: Стоимость хранения в МБ

Относительно исходного размера файла, крупные объекты были примерно на 30-35% больше. Напротив, сохранение каждой эпохи как BYTEA или SMALLINT [] [] было менее чем на 10% больше. Хранение каждого канала в виде отдельного кортежа дает увеличение на 40%, как BYTEA или SMALLINT [], что не намного хуже, чем хранение в виде большого объекта.

Одна вещь, которую я изначально не оценил, заключается в том, что «многомерные массивы должны иметь совпадающие экстенты для каждого измерения» в PostgreSQL . Это означает, что SMALLINT[][]представление работает только тогда, когда все каналы в эпоху имеют одинаковое количество выборок. Следовательно, файл C не работает с EpochArrayотношением.

С точки зрения стоимости доступа, я не играл с этим, но, по крайней мере, с точки зрения вставки данных, изначально самым быстрым было представление, EpochByteaа BlobFileс EpochChannelArrayсамым медленным - примерно в 3 раза больше, чем у первых двух.

beldaz
источник
С академической точки зрения, я нахожу ваши результаты очень интересными, но с практической точки зрения, размер хранилища является большой проблемой? Возможно, в вашем случае использования у вас очень много записей, и поэтому проблема хранения - это проблема, с которой вы сталкиваетесь? Однако в этом формате хранения любой поиск, кроме эпохи (или канала, когда он находится в соответствующей схеме), потребует чтения части каждой записи. Это нормально для вашего приложения?
Крис
Практически да, это, безусловно, важно для меня, так как я ожидаю иметь дело с несколькими ТБ необработанных файлов. Оказывается, что текущие накладные расходы ниже, чем я ожидал, но если бы это было 300% для конкретного представления, я бы, конечно, избежал этого. Что касается запросов, я не ожидал бы доступа к чему-либо, кроме эпохи и канала.
бельдаз