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 INSERT
Last 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
- 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.
- 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.
- EAV (Anti) Muster mit einer riesigen vertikalen Datentabelle mit eingeschaltetem Sharding
station_id
und monatlicher Partitionierungtimestamp
. 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. - Eine Tabelle pro
station_id
mit 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.
WHERE
Klauseln kann jedoch umständlich werden. Ich habe die Frage anAntworten:
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":
Tonnenweise Fragen wie
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:
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:
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.
quelle