PostgreSQL bytea vs smallint []

9

Ich möchte große Mehrkanal-Zeitreihendaten (100 MB - 1 GB) in eine PostgreSQL-Datenbank importieren. Die Daten stammen aus Dateien im EDF-Format , die die Daten in "Datensätze" oder "Epochen" von jeweils einigen Sekunden aufteilen. Der Datensatz jeder Epoche enthält die Signale für jeden Datenkanal als sequentielle Arrays kurzer Ganzzahlen.

Ich bin beauftragt, die Dateien in der Datenbank zu speichern, im schlimmsten Fall als BLOBs. Vor diesem Hintergrund möchte ich Optionen untersuchen, mit denen ich mehr aus den Daten in der Datenbank herausholen kann, z. B. Abfragen basierend auf den Signaldaten.

Mein ursprünglicher Plan ist es, die Daten als eine Zeile pro Epochendatensatz zu speichern. Ich versuche abzuwägen, ob die tatsächlichen Signaldaten als Bytea- oder Smallint [] - oder sogar Smallint [] [] -Typen gespeichert werden sollen. Könnte jemand eins über das andere empfehlen? Ich interessiere mich für Speicher- und Zugriffskosten. Die Verwendung wird wahrscheinlich einmal eingefügt, gelegentlich gelesen und nie aktualisiert. Wenn man sich leichter als benutzerdefinierten Typ einwickeln lässt, so dass ich Funktionen zum Analysieren von Vergleichsdatensätzen hinzufügen kann, umso besser.

Zweifellos habe ich wenig Details, also zögern Sie nicht, Kommentare zu dem hinzuzufügen, was ich klarstellen soll.

beldaz
quelle
2
Dies ist möglicherweise eine der wenigen sinnvollen Anwendungen für die Verwendung von Arrays im autorisierenden Datenmodell, da Sie viel Speicherplatz sparen, indem Sie den Zeilenaufwand von 24 bis 28 Byte vermeiden. Arrays werden auch komprimiert und außerhalb der Zeile gespeichert, wenn sie lang genug sind.
Craig Ringer
beldaz, die Art und Weise, wie Sie die Daten speichern sollten, hat viel damit zu tun, wie und wie oft Sie darauf zugreifen möchten. Wenn die Daten selten abgefragt werden und Sie die Daten immer nur auf Datensatzbasis abrufen möchten, ist eine Zeile pro Datensatz in einem Array meiner Meinung nach sinnvoll. Wenn Sie jedoch eine etwas ausführlichere Abfrage durchführen möchten, z. B. das Abrufen aller Datensätze für eine bestimmte patient_id, können wir möglicherweise eine geringfügige Verbesserung der Speicherstruktur vorschlagen. Irgendwelche Ideen zu Ihren Abfragemustern?
Chris
@ Chris Danke. Ich habe die Metadatenkomponente weggelassen, da sie sehr klein ist und sich in einer separaten Beziehung befinden kann. Abfragemuster sind TBD, aber ich möchte möglicherweise zwei verschiedene Dateien, die gleichzeitig aufgezeichnet wurden, vergleichen und Signale aus gleichzeitigen Epochen abrufen.
Beldaz
@CraigRinger Ich habe nicht viele Hinweise auf Array-Komprimierung gesehen. Muss dies auf irgendeine Weise aktiviert werden?
Beldaz

Antworten:

11

Da keine Antworten vorliegen, habe ich das Problem selbst weiter untersucht.

Es sieht so aus, als könnten benutzerdefinierte Funktionen alle Basistypen verarbeiten, einschließlich bytea und smallint[], sodass die Auswahl der Darstellung nicht wesentlich beeinflusst wird.

Ich habe verschiedene Darstellungen auf einem PostgreSQL 9.4-Server ausprobiert, der lokal auf einem Windows 7-Laptop mit Vanille-Konfiguration ausgeführt wird. Die Beziehungen zum Speichern dieser tatsächlichen Signaldaten waren wie folgt.

Großes Objekt für die gesamte Datei

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

SMALLINT-Array pro Kanal

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 pro Kanal in jeder Epoche

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-Array pro Epoche

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

BYTEA-Array pro Epoche

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

Ich habe dann eine Auswahl von EDF-Dateien über Java JDBC in jede dieser Beziehungen importiert und das Wachstum der Datenbankgröße nach jedem Upload verglichen.

Die Dateien waren:

  • Datei A: 2706 Epochen mit 16 Kanälen, jeder Kanal 1024 Samples (16385 Samples pro Epoche), 85 MB
  • Datei B: 11897 Epochen mit 18 Kanälen, jeder Kanal 1024 Samples (18432 Samples pro Epoche), 418 MB
  • Datei C: 11746 Epochen mit 20 Kanälen, jeder Kanal 64 bis 1024 Samples (17088 Samples pro Epoche), 382 MB

In Bezug auf die Speicherkosten ist hier die Größe in MB für jeden Fall belegt: Speicherkosten in MB

Im Vergleich zur ursprünglichen Dateigröße waren große Objekte etwa 30-35% größer. Im Gegensatz dazu war die Speicherung jeder Epoche als BYTEA oder SMALLINT [] [] weniger als 10% größer. Das Speichern jedes Kanals als separates Tupel ergibt eine 40% ige Erhöhung, entweder als BYTEA oder SMALLINT [], also nicht viel schlimmer als das Speichern als großes Objekt.

Eine Sache, die ich anfangs nicht gewürdigt hatte, ist, dass "Mehrdimensionale Arrays für jede Dimension übereinstimmende Ausmaße haben müssen" in PostgreSQL . Dies bedeutet, dass die SMALLINT[][]Darstellung nur funktioniert, wenn alle Kanäle in einer Epoche die gleiche Anzahl von Samples haben. Daher funktioniert Datei C nicht mit der EpochArrayBeziehung.

In Bezug auf die Zugriffskosten habe ich nicht damit herumgespielt, aber zumindest in Bezug auf das Einfügen der Daten war anfangs die schnellste Darstellung EpochByteaund BlobFilemit EpochChannelArrayder langsamsten etwa dreimal so lange wie die ersten beiden.

beldaz
quelle
Aus akademischer Sicht finde ich Ihre Ergebnisse sehr interessant, aber ist die Speichergröße aus praktischer Sicht von großer Bedeutung? Vielleicht haben Sie in Ihrem Anwendungsfall sehr viele Datensätze, und daher ist die Speicherung ein Problem, mit dem Sie konfrontiert sind? In diesem Speicherformat würde jedoch jede andere Suche als nach Epoche (oder Kanal, wenn im entsprechenden Schema) das Lesen eines Teils jedes Datensatzes erfordern. Ist das für Ihre Bewerbung in Ordnung?
Chris
Praktisch ja, das ist sicherlich wichtig für mich, da ich damit rechne, mit mehreren TB Rohdateien fertig zu werden. Wie sich herausstellt, ist der Overhead-Strom geringer als erwartet, aber wenn er für eine bestimmte Darstellung 300% betragen hätte, würde ich ihn auf jeden Fall vermeiden. Was das Abfragen betrifft, würde ich nicht erwarten, über etwas anderes als Epoche und Kanal darauf zuzugreifen.
Beldaz