PostgreSQL bytea vs smallint []


9

Sto cercando di importare dati di grandi serie multicanale (100 Mb - 1 GB) in un database PostgreSQL. I dati provengono da file in formato EDF che li raggruppano in "record" o "epoche" in genere di pochi secondi ciascuno. Il record di ogni epoca contiene i segnali per ciascun canale di dati come matrici sequenziali di interi corti.

Ho il compito di archiviare i file all'interno del database, nel peggiore dei casi come BLOB. Detto questo, mi piacerebbe studiare le opzioni che mi permetterebbero di fare qualcosa di più con i dati all'interno del database, come facilitare le query basate sui dati del segnale.

Il mio piano iniziale è quello di archiviare i dati come una riga per record di epoca. Quello che sto cercando di valutare è se memorizzare i dati del segnale effettivo come bytea o smallint [] (o anche smallint [] []). Qualcuno potrebbe raccomandare uno sopra l'altro? Sono interessato ai costi di archiviazione e di accesso. È probabile che l'utilizzo venga inserito una volta, letto occasionalmente, non aggiorni mai. Se uno fosse più facilmente racchiuso in un tipo personalizzato in modo da poter aggiungere funzioni per l'analisi del confronto dei record, tanto meglio.

Non ho dubbi sui dettagli, quindi sentiti libero di aggiungere commenti su ciò che vorresti che chiarissi.


2
Questo potrebbe essere uno dei pochi usi sensibili per l'uso dell'array nel modello di dati autorevole, poiché si risparmia molto spazio su disco evitando l'overhead della riga da 24 a 28 byte. Le matrici vengono anche compresse e archiviate fuori linea se sufficientemente lunghe.
Craig Ringer,

beldaz, il modo in cui è necessario archiviare i dati ha molto a che fare con il modo in cui si prevede di accedervi e con quale frequenza. Se i dati vengono interrogati raramente e si desidera sempre estrarre solo i dati in base al record, penso che una riga per record in un array abbia un buon senso. Tuttavia, se si desidera eseguire qualsiasi query leggermente più approfondita, ad esempio il recupero di tutti i record per un determinato ID_paziente, ad esempio, è possibile suggerire un leggero miglioramento della struttura di archiviazione. Qualche idea sui tuoi schemi di query?
Chris,

@Chris Grazie. Ho lasciato fuori il componente dei metadati poiché è molto piccolo e può risiedere in una relazione separata. I modelli di query sono TBD, ma potrei voler confrontare due diversi file registrati contemporaneamente ed estrarre segnali da epoche simultanee.
Beldaz,

@CraigRinger Non ho visto molte prove della compressione dell'array. Questo deve essere abilitato in qualche modo?
Beldaz,

Risposte:


11

In assenza di risposte ho approfondito il problema da solo.

Sembra che le funzioni definite dall'utente possano gestire tutti i tipi di base, incluso bytea e smallint[], quindi ciò non influisce molto sulla scelta della rappresentazione.

Ho provato diverse rappresentazioni su un server PostgreSQL 9.4 eseguito localmente su un laptop Windows 7 con una configurazione vanilla. Le relazioni per memorizzare i dati del segnale effettivo erano le seguenti.

Oggetto di grandi dimensioni per l'intero file

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

Matrice SMALLINT per canale

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 per canale in ogni epoca

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

Matrice 2D SMALLINT per epoca

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

Matrice BYTEA per epoca

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

Ho quindi importato una selezione di file EDF in ciascuna di queste relazioni tramite Java JDBC e ho confrontato la crescita delle dimensioni del database dopo ogni caricamento.

I file erano:

  • File A: 2706 epoche di 16 canali, ogni canale 1024 campioni (16385 campioni per epoca), 85 MB
  • File B: 11897 epoche di 18 canali, ogni canale 1024 campioni (18432 campioni per epoca), 418 MB
  • File C: 11746 epoche di 20 canali, ogni canale da 64 a 1024 campioni (17088 campioni per epoca), 382 MB

In termini di costi di archiviazione, ecco la dimensione occupata in MB per ogni caso: Costo di archiviazione in MB

Rispetto alle dimensioni del file originale, gli oggetti grandi erano circa il 30-35% più grandi. Al contrario, la memorizzazione di ogni epoca come BYTEA o SMALLINT [] [] era inferiore di oltre il 10%. La memorizzazione di ciascun canale come tupla separata aumenta del 40%, come BYTEA o SMALLINT [], quindi non molto peggio della memorizzazione come oggetto di grandi dimensioni.

Una cosa che inizialmente non avevo apprezzato è che "gli array multidimensionali devono avere estensioni corrispondenti per ogni dimensione" in PostgreSQL . Ciò significa che la SMALLINT[][]rappresentazione funziona solo quando tutti i canali di un'epoca hanno lo stesso numero di campioni. Quindi il file C non funziona con la EpochArrayrelazione.

In termini di costi di accesso, non ci ho giocato, ma almeno per quanto riguarda l'inserimento dei dati inizialmente la rappresentazione più veloce era EpochByteae BlobFile, con EpochChannelArrayla più lenta, impiegava circa 3 volte più delle prime due.


Dal punto di vista accademico, trovo i tuoi risultati molto interessanti, ma da un punto di vista pratico, la dimensione della memoria è di grande preoccupazione? Forse nel tuo caso d'uso hai molti record e quindi l'archiviazione è un problema che devi affrontare? Tuttavia, in questo formato di archiviazione, qualsiasi ricerca diversa dall'epoca (o dal canale, quando nello schema appropriato) richiederebbe la lettura di una parte di ogni record. Va bene per la tua applicazione?
Chris,

Praticamente sì, è certamente importante per me, poiché mi aspetto di gestire diversi TB di file non elaborati. A quanto pare la corrente in overhead è inferiore a quanto mi aspettassi, ma se fosse stata del 300% per una particolare rappresentazione, la eviterei sicuramente. Per quanto riguarda le query, non mi aspetterei di accedere da qualcosa di diverso dall'epoca e dal canale.
Beldaz,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.