Welches Datenmodell / -schema auf einen Zeitreihen-Datenspeicher für Datenquellen mit unterschiedlichen Feldern angewendet werden soll

7

Ich werde gebeten, einen Datenspeicher für Zeitreihendaten zu entwickeln, bin mir jedoch trotz umfangreicher Recherchen nicht sicher, welches Datenmodell und welche Speichertechnologie ich wählen soll.

Über die Daten

Die Quelldaten, die im Datenspeicher gespeichert werden sollen, werden von physikalischen Maßeinheiten bereitgestellt. Jede Einheit kann eine andere Teilmenge von Variablen mit bis zu 300 Variablen pro Messstation (z. B. Kraftstoffart, Kraftstoffverbrauch, Geschwindigkeit) haben oder nicht, während die Anzahl der verschiedenen Signale über alle Stationen in der Größenordnung von 1500 liegt Die erwartete Teilmenge der Variablen pro Station ist im Voraus bekannt. Mit der Zeit können jedoch zusätzliche Sensoren zu einer Station hinzugefügt werden (eine Schemaänderung kann im Laufe der Zeit erforderlich sein). Alle Stationen liefern Daten in unterschiedlichen Raten zwischen 20 Hz und 0,2 Hz.

Darüber hinaus steht all diesen Messstationen eine ganze Reihe von Metadaten zur Verfügung, von denen wir am Ende etwa 500 haben werden.

Die Daten kommen normalerweise stapelweise und nicht als "Echtzeit" -Stream. Die Chargengrößen unterscheiden sich von stündlichen bis monatlichen Chargen.

Über die Fragen

Die Abfrage der Daten erfolgt aus zwei Hauptgründen: Berichterstattung und statistische Analyse der Daten einer einzelnen Messstation sowie Vergleich zwischen Stationen. Etwa 80% der Anfragen beziehen sich auf Daten, die in den letzten 30 Tagen eingegangen sind. Die Abfrage erfolgt täglich, daher SELECTübersteigt die INSERTLast die Last.

Idealerweise Fragen wie

SELECT var1, var2, ... varN FROM station_data WHERE station_id=X OR station_id=Y AND TIMESTAMP BETWEEN ... AND ...;

wäre für einen einfachen Datenzugriff für Nicht-SQL-Spezialisten möglich. Darüber hinaus sollte eine einfache zeitbasierte Aggregationsarithmetik möglich sein (AVG, MAX usw. pp).

Momentane Situation

Derzeit wird eine stark normalisierte Struktur verwendet, um die Daten in einer PostgreSQL-Datenbank zu speichern, die inzwischen mit einer Tabelle pro Variable auf etwa 6 TB angewachsen ist. Jede der ungefähr 1500 Datentabellen hat die Form

(timestamp, station_id, value)

mit aktivierten Indizes (station_id), (station_id, timestamp), (timestamp)und einer eindeutigen Einschränkung (station_id, timestamp, value).

Diese Struktur erfordert eine starke äußere Verbindung (bis zu 300 äußere Verbindungen), was das Abrufen von Daten umständlich und rechenintensiv macht.

Forschung

Bisher wurden folgende Überlegungen angestellt:

DB-Technologie

  1. Während NoSQL die erforderliche Schemaflexibilität bieten würde, scheinen Tools zur Gewährleistung der Datenintegrität, Zugriffskontrolle und Verwaltung der Metadaten eine Herausforderung zu sein, und es gibt keine internen NoSQL-Erfahrungen. Darüber hinaus scheint das Lesen von Kommentaren und Antworten in diesem Sinne für eine SQL-Lösung für unseren Anwendungsfall zu sprechen.
  2. Es wurden verschiedene zeitbasisoptimierte Datenbanken berücksichtigt (hauptsächlich CrateDB und TimescaleDB ). Beide sehen im Hinblick auf ihre "automatische" Partitionierung und Sharding vielversprechend aus, bei der TimescaldeDB aufgrund seiner PostgreSQL-Basis leicht bevorzugt wäre.

Datenmodell / Schema

Bisher wurden zwei verschiedene Schemata ausgearbeitet, die im Prinzip funktionieren. Beide haben jedoch erhebliche Nachteile, die ich umgehen muss.

  1. EAV (Anti) Muster mit einer riesigen vertikalen Datentabelle mit eingeschaltetem Sharding station_idund monatlicher Partitionierung timestamp. Während die erforderliche Schemaflexibilität gegeben wäre, würde dieses Muster nicht der erforderlichen Leichtigkeit des Zugriffs entsprechen, da es immer noch stark von inneren Verknüpfungen abhängt. Darüber hinaus ist die Typensicherheit für verschiedene Datentypen auf der DB-Seite nicht gewährleistet und eine Zugriffskontrolle ist nicht möglich.
  2. Eine Tabelle pro station_idmit horizontal wechselndem Schema beim Hinzufügen eines Sensors zu einer bestimmten Station. Diese nicht normalisierte Struktur ist aus Sicht der Anwendung auf den ersten Blick ansprechend (schnelle Einfügungen, wenig Indizierung erforderlich, einfache Abfrage auf einer einzelnen Station). Das Abfragen würde jedoch dynamisches SQL erfordern, da der Endbenutzer möglicherweise den Tabellennamen für die bestimmte Station nicht kennt und ein Vergleich zwischen Stationen nur mit erweiterten SQL-Abfragen oder clientseitigem Code möglich wäre.

Allgemeine Überlegungen

Während die Speicherkapazität keine Rolle spielt, sind Zuverlässigkeit, Verfügbarkeit und Geschwindigkeit des Datenabrufs von Bedeutung.

Frage

Welches der vorgeschlagenen Datenmodelle wird bevorzugt, um die Anforderungen bei gleichzeitiger Wahrung der Skalierbarkeit zu erfüllen? Vorschläge für zusätzliche Schemata, die den Anforderungen entsprechen, sind sehr willkommen.

Vielen Dank.

K. Hueck
quelle
1
Sehr schöne erste Frage! Plus eine für die Mühe, eine detaillierte erste Frage zu stellen, die viel Aufwand mit sich brachte.
Vérace
1
Betrachten Sie vielleicht ein drittes Datenmodell: PostgreSQL (und damit TimescaleDB) unterstützt JSON- Spaltentypen. Sie könnten also ein JSON-Feld pro Tabelle haben, um viele oder alle Variablen jeder Messstation zu speichern.
TmTron
1
oh - und denken Sie daran, dass die max. Anzahl der Spalten in PostgreSQL ist 250-1600 SO Referenz
TmTron
@TmTron: Ich hielt diese Art von „wide-table-Ansatz“ nach dem Vorbild der dies . Es gilt sowohl für die Flexibilität als auch für die Aufrechterhaltung des relationalen Charakters, der für die Bereitstellung der Metadaten erforderlich ist. Das Typisieren von WHEREKlauseln kann jedoch umständlich werden. Ich habe die Frage an
K. Hueck
begrüßen solche 3. Datenmodelloptionen.
K. Hueck

Antworten:

1

Ich hatte eine ziemlich ähnliche Situation mit meinen Daten, mit Ausnahme der Variabilität der Anzahl der Variablen, aber wie TmTron sagte, könnte JSON für Sie funktionieren. Hier ist das Schema, das ich hatte (Anpassung an Ihre Daten):

Tabelle "Sensor: Enthält regelmäßig die gewünschten Metadaten über 1k + Zeilen, in einigen Fällen 7k + ohne tatsächlichen Unterschied.

Tabelle "sensor_data":

  • Zeitstempel,
  • sensor_id int, - FK zum Sensor
  • Measurement_id Int (ich hatte 14),
  • var1, var2, var3, var4, var5 - für mich ist es eine Menge von 5 int8, in Ihrem Fall sind es nicht spaltenfähige Daten, sagen wir JSON
  • Index nach (sensor_id, Mess_id, Zeitstempel) (ca. 1/3 der Tabellengröße)

Tonnenweise Fragen wie

{select timestamp, var1,var2,var3,var4,var5 from sensor_data where sensor_id = xx and timestamp between xxxx and xxxx}

Der Tisch wurde größer, langsamer abfragend, die Kunden wütender und so weiter.

Der erste Optimierungsversuch war die Partitionierung nach Bereich von sensor_ids - 20 pro Partition, der Platzverbrauch bleibt gleich, das Schema wurde komplexer, Abfragen wurden schneller, aber nicht so sehr.

Also, hier funktioniert noch Schema:

benutzerdefinierter Datentyp "Metrik" (Zeitstempel, var1, var2, var3, var4, var5)

Tabelle sensor_data:

  • Datum
  • sensor_id
  • Mess-ID
  • Datensatz - Es ist eine Spalte vom Typ "Metrik []" - Array, das alle Daten für ein Datum enthält. Eindeutiger Index nach Datum, Sensor-ID, Mess-ID

Die Auswahlabfrage wurde durch die Funktion get_data (sensor_id, Mess_id, from_time, to_time) select (unnest (Datensatz)) ersetzt. * from sensor_data wobei sensor_id = xx und Daten zwischen from_time :: date und to_time :: date und Measurement_id = xxx

Einfügen wurde komplexer:

insert into sensor_data value (to_date(timestamp), sensor, measurement, [(timestamp, var1,var2,var3,var4,var5)])
on conflict (date, sensor_id, measurement_id) do update
set dataset=dataset||excluded.dataset

Der Platzverbrauch ist ~ 10-mal geringer, die Abfrage ist komplexer, aber dramatisch schneller.

Wenn Sie keine Daten vonurement_id anfordern, entfernen Sie diese einfach aus dem Index und fragen Sie ab. Wenn Sie deutlich mehr Daten pro Tag haben, können Sie Daten pro Stunde speichern, indem Sie die Spalte "Datum" durch "Stunde" als date_trunc('hour',timestamp)und Partitionstabelle pro Monat ersetzen , sodass Sie maximal 744 (31 * 24) Zeilen pro Sensor und Messung pro Messung haben Tabelle. Es ist eine ziemlich vernünftige Anzahl von Zeilen und wird schnell genug arbeiten.

Natürlich müssen Sie Ihren eigenen Datentyp erstellen (in den meisten Fällen funktioniert der Typ (Zeitstempel, JSON)).

Die Hauptidee ist, dass postgres Datenfelder außerhalb der Tabelle speichert und sie nur liest, wenn sie benötigt werden (außerdem ist es komprimiert). So wurde die Tabelle zu einem "Index" für Daten, die an einem anderen Ort gespeichert wurden, bleibt jedoch eine Tabelle, die Sie indizieren und partitionieren können.

Die Einschränkung besteht darin, dass Sie den Inhalt von Dataset-Arrays nicht mit Einschränkungen steuern und Daten direkt aggregieren können. Bei einfachen Aggregationen (wie max, min, avg) können Sie Daten jedoch voraggregieren und dennoch auf Zeilenebene speichern.

Dzhureedzh
quelle