PostgreSQL bytea vs smallint []


9

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

Мені доручено зберігати файли в базі даних, в гіршому випадку - BLOB. Враховуючи це, я хотів би вивчити варіанти, які дозволять мені зробити щось більше з даними в базі даних, наприклад полегшення запитів на основі даних сигналу.

Мій початковий план - зберігати дані як один рядок на запис епохи. Що я намагаюся зважити, - чи зберігати фактичні дані сигналу у вигляді байтів або smallint [] (або навіть smallint [] []). Хтось може порекомендувати один за іншим? Мене цікавлять витрати на зберігання та доступ. Використання, ймовірно, буде вставлено один раз, читати періодично, ніколи не оновлювати. Якби хтось був легше загорнутий як власний тип, такий, що я міг би додати функції для аналізу порівняння записів, то тим більше, тим краще.

Без сумніву, я недостатньо деталізований, тому не соромтесь додавати коментарі до того, що ви хочете, щоб я уточнив.


2
Це може бути одним з небагатьох розумних застосувань для використання масиву в авторській моделі даних, оскільки ви економите багато дискового простору, уникаючи накладних рядків від 24 до 28 байтів. Масиви також стискаються та зберігаються поза мережею, якщо досить довго.
Крейг Рінгер

beldaz, спосіб зберігання даних має багато спільного з тим, як ви плануєте отримати доступ до них та як часто. Якщо дані рідко запитуються, і ви завжди хочете просто витягувати дані на основі запису, то я думаю, що один рядок на запис у масиві має сенс. Однак, якщо ви хочете виконати будь-який запит, який є трохи більш глибоким, наприклад, підтягуючи всі записи для певного пацієнта_id, наприклад, то, можливо, ми можемо запропонувати незначне вдосконалення структури пам’яті. Якісь ідеї щодо ваших моделей запитів?
Кріс

@Chris Дякую Я залишив компонент метаданих, оскільки це дуже мало і може знаходитися в окремому відношенні. Шаблони запитів - це TBD, але я, можливо, хочу порівнювати два різні файли, записані одночасно, і витягувати сигнали з одночасних епох.
beldaz

@CraigRinger Я не бачив великих доказів стиснення масиву. Чи потрібно це якось увімкнути?
beldaz

Відповіді:


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 рази довше, ніж перші два.


З точки зору академічної точки зору, я вважаю ваші результати дуже цікавими, але з практичної точки зору, чи викликає велике занепокоєння розмір сховища? Можливо, у вашому випадку використання дуже багато записів, і тому зберігання - це проблема, з якою ви стикаєтесь? Однак у цьому форматі зберігання будь-який пошук, окрім епохи (або каналу, якщо є у відповідній схемі), потребує зчитування частини кожного запису. Чи це добре для вашої заявки?
Кріс

Практично так, це, безумовно, важливо для мене, так як я очікую, що я матиму справу з декількома ТБ необроблених файлів. Як виявляється, струм у накладних витратах нижчий, ніж я очікував, але якби він становив 300% для конкретного представлення, я, безумовно, уникну цього. Щодо запитів, я не очікував би доступу до них, окрім епохи та каналу.
beldaz
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.