2016-09-03 4 views
0

Ich muss meine kleine große Datenbank optimieren, weil es zu langsam ist, vielleicht finden wir eine andere Lösung zusammen.Eine andere Möglichkeit, Datenbankstruktur zu erstellen

Zunächst sprechen wir über Daten, die in der Datenbank gespeichert sind. Es gibt zwei Objekte: users und sagen wir mal, messages

Benutzer

Es ist so etwas wie das:

+----+---------+-------+-----+ 
| id | user_id | login | etc | 
+----+---------+-------+-----+ 
| 1 | 100001 | A | ....| 
| 2 | 100002 | B | ....| 
| 3 | 100003 | C | ....| 
|... | ...... | ... | ....| 
+----+---------+-------+-----+ 

Es gibt kein Problem innerhalb dieser Tabelle ist. (Haben Sie keine Angst von id und user_id. user_id von einer anderen Anwendung verwendet wird, so hat es hier zu sein.)

Nachrichten

Und die zweite Tabelle hat ein Problem. Jeder Benutzer hat zum Beispiel Meldungen wie diese:

+----+---------+------+----+ 
| id | user_id | from | to | 
+----+---------+------+----+ 
| 1 | 1  | aab | bbc| 
| 2 | 2  | vfd | gfg| 
| 3 | 1  | aab | bbc| 
| 4 | 1  | fge | gfg| 
| 5 | 3  | aab | gdf| 
|... | ...... | ... | ...| 
+----+---------+------+----+ 

Es gibt keine Notwendigkeit, edit Nachrichten, aber es sollte eine Gelegenheit sein, um die Liste der Meldungen für den Benutzer aktualisiert. Zum Beispiel sendet ein externer Dienst alle Nachrichten des Benutzers an die Datenbank und die Liste muss aktualisiert werden. Und das Wichtigste ist, dass es etwa 30 Millionen Benutzer gibt und der durchschnittliche Benutzer mehr als 500 Nachrichten hat. Ein weiteres Problem, das ich durch das Feld from suchen und die Anzahl der Übereinstimmungen berechnen muss. Ich habe eine einfache SQL-Abfrage mit Join entworfen, aber es dauert zu viel Zeit, um die Daten zu erhalten.

Also ... es ist ziemlich viel Datenmenge. Ich entschied mich, RDS nicht zu benutzen (ich benutzte Postgresql) und entschied mich, zu Datenbanken wie Clickhouse und so weiter zu gehen.

Allerdings habe ich mit einem Problem konfrontiert, dass zum Beispiel Clickhouse keine UPDATE Anweisung unterstützt.

Um dieses Problem zu beheben, entschied ich mich, Nachrichten als eine Zeile zu speichern. So ist die Tabelle Messages sollte wie folgt sein:

    Here I'd like to store messages in JSON format 
       {"from":"aaa", "to":bbe"} 
       {"from":"ret", "to":fdd"} 
       {"from":"gfd", "to":dgf"} 
        ||       
        \/ 
+----+---------+----------+------+ And there I'd like to store the 
| id | user_id | messages | hash | <= hash of the messages. 
+----+---------+----------+------+ 

Ich denke, dass die Volltextsuche innerhalb der messages Spalte wird einige Zeit Ressourcen sparen und so weiter.

Haben Sie irgendwelche Ideen? :)

+0

Ich muss sagen, dass Ihre Frage sehr breit ist. Zuallererst, welche Typen sind von und zu Spalten? Zweitens, wie haben Sie Indizes verwendet, als Sie PostgreSQL verwendet haben? Hast du Partitionen untersucht? –

+0

'from' und' to' ist varchar (255) und ich habe nicht in Partitionen gesucht ... Könnten Sie ein Tutorial zur Verfügung stellen? – Ascelhem

Antwort

0

Zunächst einmal, wenn wir einen so großen Datensatz haben, sollten from und to Spalten möglichst ganze Zahlen sein, da deren Vergleich schneller ist.

Zweitens sollten Sie in Betracht ziehen, korrekte Indizes zu erstellen. Da jeder Benutzer relativ wenige Datensätze hat (500 im Vergleich zu 30 Millionen insgesamt), sollte es Ihnen einen enormen Leistungsvorteil bringen.

Wenn alles andere fehlschlägt, sollten Sie Partitionen mit:

https://www.postgresql.org/docs/9.1/static/ddl-partitioning.html

In Ihrem Fall würde sie dynamisch sein, und behindern ersten Mal ungeheuer einfügt, so würde ich halte sie nur zuletzt, wenn sehr effizient, Erholungsort.

2

In ClickHouse ist der optimale Weg, Daten in "großen flachen Tisch" zu speichern. So speichern Sie jede Nachricht in einer separaten Zeile. 15 Milliarden Zeilen ist Ok für ClickHouse, auch auf einzelnen Knoten.

Außerdem ist es sinnvoll, jeden Benutzer direkt in der Nachrichten-Tabelle (pre-joined) zu haben, so dass Sie keine JOINs machen müssen. Es ist geeignet, wenn Benutzerattribute nicht aktualisiert werden.

Diese Attribute haben wiederholte Werte für die Nachricht jedes Benutzers - es ist OK, weil ClickHouse Daten gut komprimiert, insbesondere wiederholte Werte.

Wenn die Benutzerattribute aktualisiert werden, sollten Sie in Erwägung ziehen, die Benutzertabelle in einer separaten Datenbank zu speichern und die Funktion "Externe Wörterbücher" zu verwenden.

Wenn die Nachricht aktualisiert wird, aktualisieren Sie sie einfach nicht. Schreiben Sie stattdessen eine andere Zeile mit geänderter Nachricht in eine Tabelle und belassen Sie die alte Nachricht unverändert.

Es ist wichtig, den richtigen Primärschlüssel für Ihren Tisch zu haben. Sie sollten die Tabelle aus der MergeTree-Familie verwenden, die die Daten ständig nach Primärschlüssel umordnet und so die Effizienz von Bereichsabfragen aufrechterhält. Der Primärschlüssel muss nicht eindeutig sein, zum Beispiel könnten Sie Primärschlüssel als nur (von) definieren, wenn Sie häufig "von = ..." schreiben würden, und wenn diese Abfragen in kurzer Zeit verarbeitet werden müssen.

Und Sie könnten user_id als Primärschlüssel verwenden: Wenn Abfragen nach Benutzer-ID sind häufig und müssen so schnell wie möglich verarbeitet werden, aber Abfragen mit Prädikat auf 'von' wird ganze Tabelle scannen (bedenken Sie, dass ClickHouse effizient scannen effizient).

Wenn Sie schnell nach vielen verschiedenen Attributen suchen müssen, können Sie einfach Tabellen mit verschiedenen Primärschlüsseln duplizieren. Normalerweise wird die Tabelle ausreichend komprimiert, und Sie können es sich leisten, Daten in wenigen Kopien mit unterschiedlicher Reihenfolge für verschiedene Bereichsabfragen zu haben.

Verwandte Themen