Nehmen wir als vereinfachtes Beispiel an, ich habe eine Tabelle wie diese:
seq | value
----+------
102 | 11954
211 | 43292
278 | 19222
499 | 3843
Die Tabelle kann Hunderte Millionen Datensätze enthalten, und ich muss häufig folgende Abfragen durchführen:
SELECT sum(value) WHERE seq > $a and seq < $b
Selbst wenn seq
es indiziert ist, durchläuft eine typische Datenbankimplementierung jede Zeile, um die Summe im besten Fall zu berechnen O(n)
, wobei n
die Größe des Bereichs ist.
Gibt es eine Datenbank, die dies effizient durchführen kann, wie in der O(log(n))
Abfrage angegeben?
Ich bin auf eine Datenstruktur gestoßen, die als Segmentbaum bezeichnet wird, wie hier beschrieben . Wird manchmal auch als Bereichsbaum oder Intervallbaum bezeichnet, obwohl alle diese Namen häufig als geringfügig unterschiedliche Variation der Datenstruktur beschrieben werden.
Ich bin jedoch auf keine Datenbank gestoßen, die eine solche Datenstruktur implementiert. Die Implementierung von Grund auf ist für eine In-Memory-Struktur einfach, wird jedoch schwierig, wenn sie beibehalten werden muss oder zu groß ist, um in den Speicher zu passen. Wenn es ein effizientes Muster gibt, um dies zusätzlich zu einer vorhandenen Datenbank zu implementieren, könnte dies ebenfalls hilfreich sein.
Randnotiz: Dies ist keine Nur-Anhängen-Tabelle, daher funktioniert eine Lösung wie das Beibehalten einer kumulativen Summe in diesem Fall nicht.
Antworten:
Verwenden von SQL Server ColumnStore- Indizes
Okay, nur einer - ein Cluster-CS-Index.
Wenn Sie mehr über die Hardware erfahren möchten, auf der ich dies getan habe, klicken Sie hier . Vollständige Offenlegung, ich schrieb diesen Blog-Beitrag auf der Website des Unternehmens, für das ich arbeite.
Auf zum Test!
Hier ist ein allgemeiner Code zum Erstellen einer ziemlich großen Tabelle. Dieselbe Warnung wie bei Evan, das Erstellen und Indizieren kann eine Weile dauern.
Nun, gewinnt Evan der Einfachheit halber, aber ich habe darüber gesprochen , dass vor.
Hier ist die Indexdefinition. La und dee und dah.
Bei einer Zählung hat jede ID eine ziemlich gleichmäßige Verteilung:
Ergebnisse:
...
Mit jeder ID mit ~ 5.005.005 Zeilen können wir uns einen ziemlich kleinen Bereich von IDs ansehen, um eine Summe von 10 Millionen Zeilen zu erhalten.
Ergebnis:
Abfrageprofil:
Zum Spaß eine größere Aggregation:
Ergebnisse:
Abfrageprofil:
Hoffe das hilft!
quelle
PostgreSQL mit einem BRIN-Index
Das ist nicht wahr. Zumindest wird das keine anständige Datenbank tun. PostgreSQL unterstützt das Erstellen von BRIN-Indizes für diese Art von Tabellen. BRIN-Indizes sind sehr klein und passen sogar in so große Tabellen. Hunderte Millionen Zeilen sind nichts.
Hier werden 300 Millionen Zeilen so definiert, wie Sie sie bestellt haben. Die Erstellung kann lange dauern (Zeit: 336057.807 ms + 95121.809 ms für den Index).
Und nun...
1,4 Sekunden, um 5.889.135 Zeilen im angegebenen Bereich zu aggregieren / zu summieren.
Obwohl die Tabelle 10 GB umfasst, beträgt der BRIN-Index 304 kB.
Noch schneller
Wenn dies immer noch nicht schnell genug ist, können Sie die Aggregate in 100.000 Zeilen zwischenspeichern.
Jetzt müssen Sie nur noch die
2(1e5-1)
Zeilen " Brin" und "Aggregate" verwenden, anstatt 300 Millionen oder was auch immer.Hardware
Lenovo x230, i5-3230M, 16 GB RAM, 1 TB Samsung 840 SSD.
quelle
O(n)
vielleichtO(sqrt(n))
. Hängt davon ab, wie Sie die Intervalle definieren, die für die Materialisierung verwendet werden sollen.