
Da ClickHouse ein spezialisiertes System ist, ist es beim Einsatz wichtig, die Besonderheiten seiner Architektur zu berücksichtigen. In diesem Bericht wird Alexej Beispiele typischer Fehler beim Einsatz von ClickHouse vorstellen, die zu einer ineffizienten Nutzung führen können. An praktischen Beispielen wird gezeigt, wie die Wahl einer bestimmten Datenschema die Leistung erheblich verändern kann.
Hallo zusammen! Mein Name ist Alexej, ich arbeite mit ClickHouse.

Zunächst möchte ich euch erfreuen, dass ich euch heute nicht erzählen werde, was ClickHouse ist. Ehrlich gesagt, ich habe genug davon. Ich erkläre immer wieder, was es ist. Und wahrscheinlich wissen es schon alle.

Stattdessen werde ich darüber sprechen, welche möglichen Stolpersteine es gibt, d. h. wie man ClickHouse falsch benutzen kann. Tatsächlich braucht man keine Angst zu haben, denn wir entwickeln ClickHouse als ein System, das einfach, benutzerfreundlich ist und sofort funktioniert. Man installiert es und fertig, keine Probleme.
Es ist jedoch zu beachten, dass dieses System spezialisiert ist und man leicht auf ungewöhnliche Nutzungsszenarien stoßen kann, die das System aus der Komfortzone bringen.
Also, welche Stolpersteine gibt es? Ich werde hauptsächlich über offensichtliche Dinge sprechen. Allen ist alles offensichtlich, alle verstehen alles und können sich freuen, dass sie so clever sind, während diejenigen, die es nicht verstehen, etwas Neues erfahren werden.

Ein ganz einfaches Beispiel, das leider häufig vorkommt, ist die große Anzahl an Inserts mit kleinen Batches, d. h. eine große Anzahl kleiner Inserts.
Wenn man sich ansieht, wie ClickHouse Inserts ausführt, kann man mit einem einzigen Befehl auch einen Datenstrom von einem Terabyte senden. Das ist kein Problem.
Schauen wir uns die typische Leistung an. Zum Beispiel haben wir eine Tabelle mit Daten aus Yandex.Metrica. Hits. 105 irgendwelche Spalten. 700 Bytes im unkomprimierten Zustand. Und wir werden ordentliche Batches mit einer Million Zeilen einfügen.
Wir fügen in die MergeTree-Tabelle ein, und es ergibt sich eine halbe Million Zeilen pro Sekunde. Hervorragend. In der replizierten Tabelle wird es etwas weniger, etwa 400.000 Zeilen pro Sekunde.
Wenn man die Quorum-Insertion einschaltet, erhält man etwas weniger, aber immer noch eine respektable Leistung, 250.000 Zeilen pro Sekunde. Die Quorum-Insertion ist eine undocumented feature in ClickHouse*.
* Stand 2020, .

Was passiert, wenn man es schlecht macht? Wir fügen eine Zeile nach der anderen in die MergeTree-Tabelle ein, und es entstehen 59 Zeilen pro Sekunde. Das ist 10.000 Mal langsamer. Beim ReplicatedMergeTree sind es 6 Zeilen pro Sekunde. Wenn dann noch ein Quorum aktiviert wird, sind es nur 2 Zeilen pro Sekunde. Meiner Meinung nach ist das einfach unerträglich. Wie kann man so träge sein? Sogar auf meinem T-Shirt steht, dass ClickHouse nicht träge sein sollte. Aber trotzdem passiert es manchmal.

Tatsächlich ist das unser Fehler. Wir hätten es problemlos so einrichten können, dass alles normal funktioniert, aber wir haben es nicht getan. Und wir haben es nicht getan, weil es für unser Szenario nicht erforderlich war. Wir hatten bereits Chargen. Daten wurden einfach in Chargen zu uns eingespielt, und es gab keine Probleme. Wir fügen ein, und alles funktioniert normal. Aber natürlich sind verschiedene Szenarien möglich. Zum Beispiel, wenn Sie eine Reihe von Servern haben, auf denen Daten generiert werden. Und sie fügen Daten nicht so oft ein, aber es gibt trotzdem häufige Einfügungen. Und das muss man irgendwie vermeiden.
Technisch gesehen besteht das Problem darin, dass, wenn Sie einen Insert in ClickHouse durchführen, die Daten nicht in eine Memtable gelangen. Wir haben nicht einmal einen echten log structure MergeTree, sondern einfach nur einen MergeTree, weil es kein Log und keine MemTable gibt. Wir schreiben die Daten sofort in das Dateisystem, bereits nach Spalten sortiert. Und wenn Sie 100 Spalten haben, müssen mehr als 200 Dateien in ein separates Verzeichnis geschrieben werden. Das ist ziemlich unhandlich.

Und die Frage stellt sich: „Wie macht man es richtig?“, wenn eine solche Situation entsteht, dass man die Daten dennoch irgendwie in ClickHouse einfügen muss.
Methode 1. Das ist die einfachste Methode. Verwenden Sie irgendeine verteilte Warteschlange. Zum Beispiel Kafka. Sie nehmen einfach die Daten aus Kafka heraus, batchen einmal pro Sekunde. Und alles wird gut, Sie schreiben es ein, alles funktioniert normal.
Die Nachteile sind, dass Kafka ein weiteres unhandliches verteiltes System ist. Ich verstehe, wenn Sie bereits Kafka in Ihrem Unternehmen haben. Das ist gut, das ist praktisch. Aber wenn nicht, sollten Sie dreimal nachdenken, bevor Sie sich einen weiteren verteilten System in Ihr Projekt holen. Daher sollten Sie Alternativen in Betracht ziehen.

Methode 2. Eine solche altmodische Alternative, die dabei sehr einfach ist. Sie haben einen Server, der Ihre Protokolle generiert. Er speichert Ihre Protokolle einfach in einer Datei. Und einmal pro Sekunde benennen wir diese Datei um und öffnen eine neue. Und ein separates Skript, entweder per Cronjob oder ein Daemon, nimmt die älteste Datei und schreibt sie in ClickHouse. Wenn man die Protokolle einmal pro Sekunde schreibt, funktioniert alles wunderbar.
Der Nachteil dieser Methode ist jedoch, dass, wenn Ihr Server, auf dem die Protokolle generiert werden, verschwindet, auch die Daten verschwinden.

Methode 3. Es gibt eine weitere interessante Methode, die überhaupt ohne temporäre Dateien auskommt. Zum Beispiel haben Sie eine Art von Werbekreisel oder einen anderen interessanten Daemon, der Daten generiert. Sie können eine Sammlung von Daten direkt im Arbeitsspeicher, im Puffer, speichern. Und wenn eine bestimmte Zeit vergangen ist, legen Sie diesen Puffer beiseite, erstellen einen neuen, und in einem separaten Thread fügen Sie die bereits angesammelten Daten in ClickHouse ein.
Andererseits verschwinden die Daten auch bei einem kill -9. Wenn Ihr Server abstürzt, verlieren Sie diese Daten. Ein weiteres Problem ist, dass, wenn Sie nicht in die Datenbank schreiben können, die Daten im Arbeitsspeicher angesammelt werden. Entweder läuft der Arbeitsspeicher voll, oder Sie verlieren einfach die Daten.

Methode 4. Noch eine interessante Methode. Sie haben irgendeinen Serverprozess. Und er kann Daten sofort an ClickHouse senden, aber das in einer einzelnen Verbindung. Zum Beispiel senden Sie eine HTTP-Anfrage mit transfer-encoding: chunked mit einem Insert. Und er generiert die Chunks nicht zu selten, Sie können jede Zeile senden, obwohl es Overhead für das Framing dieser Daten geben wird.
Nichtsdestotrotz werden in diesem Fall die Daten sofort an ClickHouse gesendet. Und ClickHouse wird sie selbst puffern.
Aber auch hier treten Probleme auf. Jetzt verlieren Sie Daten auch dann, wenn Ihr Prozess abstürzt, und, wenn der ClickHouse-Prozess abstürzt, weil dies einen unvollendeten Insert bedeutet. In ClickHouse sind Inserts atomar bis zu einem bestimmten angegebenen Schwellenwert hinsichtlich der Zeilenanzahl. Prinzipiell ist das eine interessante Methode. Kann ebenfalls verwendet werden.

Methode 5. Hier ist eine weitere interessante Methode. Dies ist ein von der Community entwickelter Server für das Batch-Processing von Daten. Ich habe mir das nicht selbst angeschaut, daher kann ich nichts garantieren. Allerdings werden auch für ClickHouse keine Garantien gegeben. Das ist ebenfalls Open Source, aber auf der anderen Seite haben Sie sich vielleicht an einen bestimmten Qualitätsstandard gewöhnt, den wir zu liefern versuchen. Für dieses Ding – ich weiß nicht, schauen Sie auf GitHub vorbei, sehen Sie sich den Code an. Vielleicht haben sie etwas Brauchbares geschrieben.
* Stand 2020, sollte ebenfalls zur Überlegung hinzugefügt werden .

Methode 6. Eine weitere Möglichkeit ist die Nutzung von Buffer-Tabellen. Der Vorteil dieser Methode ist, dass es sehr einfach ist, sie zu verwenden. Sie erstellen eine Buffer-Tabelle und fügen Daten hinzu.
Der Nachteil ist, dass das Problem nicht vollständig gelöst wird. Wenn Sie beim Einfügen von MergeTree-Daten pro Sekunde ein Batch gruppieren müssen, müssen Sie beim Einfügen in eine Buffer-Tabelle mindestens einige Tausend pro Sekunde gruppieren. Wenn es mehr als 10.000 pro Sekunde sind, wird es immer noch problematisch. Und wenn Sie in Batches einfügen, sehen Sie, dass es dort Hunderttausende von Zeilen pro Sekunde gibt. Und das bereits mit relativ großen Daten.
Und auch Buffer-Tabellen haben kein Protokoll. Wenn mit Ihrem Server etwas nicht stimmt, gehen die Daten verloren.

Und als Bonus haben wir kürzlich die Möglichkeit hinzugefügt, Daten aus Kafka abzurufen. Es gibt eine Tabellen-Engine – Kafka. Sie erstellen es einfach. Und dazu können Sie materialisierte Ansichten hinzufügen. In diesem Fall wird es die Daten selbst aus Kafka holen und in die benötigten Tabellen einfügen.
Was mich besonders freut, ist, dass diese Möglichkeit nicht von uns erstellt wurde. Es ist ein Community-Feature. Und wenn ich "Community-Feature" sage, meine ich das ohne jegliche Abwertung. Wir haben den Code gelesen, Reviews gemacht, es sollte normal funktionieren.
* Stand 2020, gab es ähnliche Unterstützung für .

Was könnte beim Einfügen von Daten unbequem oder unerwartet sein? Wenn Sie eine INSERT VALUES-Anfrage stellen und in den VALUES einige berechnete Ausdrücke schreiben. Zum Beispiel ist now() auch ein berechneter Ausdruck. Und in diesem Fall muss ClickHouse für jede Zeile den Interpreter dieser Ausdrücke ausführen, und die Leistung wird dramatisch sinken. Es ist besser, dies zu vermeiden.
* Das Problem ist derzeit vollständig gelöst, es gibt keine Leistungsverschlechterung mehr bei der Verwendung von Ausdrücken in VALUES.
Ein weiteres Beispiel für Probleme, die auftreten können, wenn in einem Batch Daten auf mehrere Partitionen verteilt sind. Standardmäßig partitioniert ClickHouse nach Monaten. Wenn Sie also einen Batch von einer Million Zeilen einfügen und die Daten mehrere Jahre abdecken, haben Sie mehrere Dutzend Partitionen. Das entspricht der Tatsache, dass es in Wirklichkeit viele kleinere Batches gibt, da die Daten zunächst nach Partitionen aufgeteilt werden.
* Kürzlich wurde in ClickHouse im experimentellen Modus die Unterstützung für das kompakte Format von Stücke und Stücke im Arbeitsspeicher mit Write-Ahead-Log hinzugefügt, was das Problem nahezu vollständig löst.

Lassen Sie uns nun die zweite Art von Problemen betrachten – die Typisierung von Daten.
Es gibt strenge und stringbasierte Typisierung. Stringbasiert bedeutet, dass Sie einfach erklärt haben, alle Felder seien vom Typ string. Das ist nicht ideal. So sollte man es nicht machen.
Lassen Sie uns klären, wie man es richtig macht, wenn man sagen möchte, dass ein bestimmtes Feld ein String ist, und ClickHouse die Arbeit erledigen soll, ohne dass ich mir dabei viel Mühe machen muss. Es ist jedoch trotzdem wichtig, einige Anstrengungen zu unternehmen.

Nehmen wir beispielsweise eine IP-Adresse. In einem Fall haben wir sie als String gespeichert, etwa 192.168.1.1. In einem anderen Fall wird sie eine Zahl des Typs UInt32* sein. 32 Bit sind ausreichend für eine IPv4-Adresse.
Erstens, auch wenn es seltsam klingt, wird die Datenkomprimierung ungefähr gleich sein. Es wird sicher Unterschiede geben, aber nicht so große. Daher gibt es beim Festplattendurchsatz keine gravierenden Probleme.
Aber es gibt einen erheblichen Unterschied in der CPU-Zeit und der Ausführungszeit der Abfrage.
Berechnen wir die Anzahl der einzigartigen IP-Adressen, wenn sie als Zahlen gespeichert sind. Das ergibt 137 Millionen Zeilen pro Sekunde. Wenn es dasselbe in Form von Strings ist, dann 37 Millionen Zeilen pro Sekunde. Ich weiß nicht, warum es diese Übereinstimmung gibt. Ich habe diese Abfragen selbst ausgeführt. Dennoch ist es etwa viermal langsamer.
Wenn wir den Unterschied im Speicherplatz auf der Festplatte berechnen, gibt es auch einen Unterschied. Und dieser Unterschied beträgt etwa ein Viertel, weil es viele einzigartige IP-Adressen gibt. Wenn es hier Zeilen mit einer geringen Anzahl verschiedener Werte gäbe, könnten diese problemlos nach dem Wörterbuch in etwa gleichem Umfang komprimiert werden.
Und ein vierfacher Zeitunterschied auf der Straße liegt nicht einfach so herum. Vielleicht ist es Ihnen egal, aber wenn ich so einen Unterschied sehe, macht mich das traurig.

Lassen Sie uns verschiedene Fälle betrachten.
1. Ein Fall, wenn Sie nur wenige unterschiedliche eindeutige Werte haben. In diesem Fall verwenden wir eine einfache Praxis, die Sie wahrscheinlich kennen und in allen Datenbanksystemen nutzen können. Das gilt nicht nur für ClickHouse. Sie speichern einfach numerische Identifikatoren in der Datenbank. Und die Umwandlung in Strings und zurück können Sie dann in Ihrer Anwendung vornehmen.
Nehmen wir an, Sie haben eine Region. Und Sie versuchen, sie als String zu speichern. Dort steht dann: Moskau und MO. Und wenn ich sehe, dass dort „Moskau“ steht, ist das noch in Ordnung, aber wenn auch MO auftaucht, wird es schon irgendwie traurig. Das sind schließlich viele Bytes.
Stattdessen speichern wir einfach die Zahl Ulnt32 und 250. Bei uns sind es 250 in Yandex, bei Ihnen mag es anders sein. Nur für den Fall möchte ich darauf hinweisen, dass ClickHouse eine integrierte Möglichkeit hat, mit geografischen Datenbanken zu arbeiten. Sie speichern einfach ein Verzeichnis mit Regionen, einschließlich hierarchischer Strukturen, d. h. dort wird es Moskau, MO und alles, was Sie brauchen, geben. Und Sie können auf Abfrageebene konvertieren.

Die zweite Option ist im Grunde die gleiche, hat aber bereits Unterstützung innerhalb von ClickHouse. Das ist der Datentyp Enum. Sie definieren einfach alle benötigten Werte innerhalb des Enum. Zum Beispiel den Gerätetyp, und dort schreiben Sie: Desktop, Mobil, Tablet, Fernseher. Insgesamt 4 Varianten.
Der Nachteil ist, dass man gelegentlich ein Alter durchführen muss. Man hat nur eine Variante hinzugefügt. Wir führen alter table durch. Tatsächlich ist alter table in ClickHouse kostenlos. Besonders kostenlos für Enum, da sich die Daten auf der Festplatte nicht ändern. Dennoch erfordert das Alter eine Sperre für die Tabelle und muss warten, bis alle select-Befehle abgeschlossen sind. Erst danach wird das Alter ausgeführt, d. h. einige Unannehmlichkeiten bleiben vorhanden.
* In aktuellen Versionen von ClickHouse ist ALTER vollständig nicht blockierend.

Eine weitere Option, die für ClickHouse recht einzigartig ist, ist die Anbindung externer Verzeichnisse. Sie können Zahlen in ClickHouse speichern und Ihre Verzeichnisse in einem beliebigen für Sie bequemen System halten. Zum Beispiel kann man MySQL, Mongo, Postgres verwenden. Man kann sogar einen eigenen Mikroservice erstellen, der diese Daten über HTTP bereitstellt. Und auf der Ebene von ClickHouse schreiben Sie eine Funktion, die diese Daten von Zahlen in Strings umwandelt.
Dies ist eine spezialisierte, aber sehr effektive Methode, um einen Join mit einer externen Tabelle durchzuführen. Dabei gibt es zwei Varianten. In der einen Variante werden die Daten vollständig zwischengespeichert, sind vollständig im Arbeitsspeicher vorhanden und werden mit einer gewissen Periodizität aktualisiert. In der anderen Variante, wenn diese Daten nicht in den Arbeitsspeicher passen, können sie teilweise zwischengespeichert werden.
Hier ein Beispiel. Es gibt Yandex.Direct. Dort gibt es eine Werbekampagne und Banner. Wahrscheinlich gibt es etwa zehn Millionen Werbekampagnen. Diese passen ungefähr in den Arbeitsspeicher. Bei den Bannern hingegen – Milliarden, die passen nicht. Und wir nutzen ein zwischenspeicherbares Wörterbuch aus MySQL.
Das einzige Problem ist, dass das zwischenspeicherbare Wörterbuch nur gut funktioniert, wenn die Trefferquote nahe bei 100 % liegt. Wenn sie geringer ist, muss man bei der Verarbeitung von Anfragen für jede Datenmenge tatsächlich die fehlenden Schlüssel holen und die Daten aus MySQL abfragen. Bei ClickHouse kann ich mich jedoch darauf verlassen, dass es nicht bremst; über andere Systeme möchte ich nichts sagen.
Als Bonus ist zu erwähnen, dass Wörterbücher eine sehr einfache Möglichkeit sind, Daten in ClickHouse nachträglich zu aktualisieren. D. h., wenn Sie einen Bericht über die Werbekampagnen hatten, hat der Benutzer einfach die Werbekampagne geändert und in allen alten Daten, in allen Berichten, wurden diese Daten ebenfalls geändert. Wenn man Daten direkt in die Tabelle schreiben würde, wäre eine Aktualisierung nicht möglich.

Eine weitere Methode, wenn Sie nicht wissen, woher Sie die Identifikatoren für Ihre Zeilen beziehen sollen, ist, sie einfach zu hashen. Der einfachste Weg besteht darin, einen 64-Bit-Hash zu verwenden.
Das einzige Problem ist, dass, wenn der Hash 64 Bit beträgt, Kollisionen fast sicher auftreten werden. Denn wenn es viel mehr als eine Milliarde Zeilen gibt, wird die Wahrscheinlichkeit merklich spürbar.
Es wäre auch nicht ideal, die Namen der Werbekampagnen so zu hashen. Wenn die Werbekampagnen von verschiedenen Unternehmen durcheinander geraten, wird es unverständlich.
Es gibt einen einfachen Trick. Es stimmt, dass es für ernsthafte Daten nicht sehr geeignet ist, aber wenn es etwas weniger Ernstes ist, fügen Sie einfach die Kunden-ID zu dem Wörterbuchschlüssel hinzu. Dann werden Sie zwar Kollisionen haben, aber nur innerhalb eines Kunden. So wird es bei uns für die Linkkarten in Yandex.Metrica verwendet. Wir haben dort URLs, wir speichern Hashes. Und wir wissen, dass es natürlich Kollisionen gibt. Aber wenn die Seite angezeigt wird, ist die Wahrscheinlichkeit, dass genau auf einer Seite bei einem Benutzer einige URLs verschwommen wurden und dass dies überhaupt bemerkt wird, vernachlässigbar.
Als Bonus – für viele Operationen reichen einfach die Hashes, und die eigentlichen Strings müssen nirgendwo gespeichert werden.

Ein anderes Beispiel: Wenn die Strings kurz sind, beispielsweise die Domains von Websites. Diese können genau so gespeichert werden. Oder zum Beispiel die Sprache des Browsers ru – 2 Byte. Es tut mir natürlich leid um die kleinen Bytes, aber machen Sie sich keine Sorgen, 2 Byte sind nicht viel. Bitte, speichern Sie, wie es ist, machen Sie sich keinen Kopf.

Ein anderer Fall ist, wenn es umgekehrt sehr viele Strings gibt, und in ihnen sehr viele einzigartige, und zudem eine potenziell unbegrenzte Vielzahl. Ein typisches Beispiel sind Suchanfragen oder URLs. Suchanfragen, auch aufgrund von Tippfehlern. Schauen wir, wie viele einzigartige Suchanfragen an einem Tag vorkommen. Es stellt sich heraus, dass es fast die Hälfte aller Ereignisse sind. In diesem Fall könnten Sie denken, dass die Daten normalisiert werden müssen, IDs gezählt werden und in einer separaten Tabelle gespeichert werden sollten. Aber das muss nicht sein. Speichern Sie diese Strings einfach, wie sie sind.
Besser – erfinden Sie nichts, denn wenn Sie sie separat speichern, ist ein Join erforderlich. Und dieser Join ist im besten Fall ein zufälliger Zugriff auf den Speicher, falls er überhaupt in den Speicher passt. Wenn nicht, gibt es überhaupt Probleme.
Wenn die Daten jedoch in Place gespeichert werden, werden sie einfach in der benötigten Reihenfolge aus dem Dateisystem gelesen und alles ist in Ordnung.

Wenn Sie URLs oder eine andere komplexe lange Zeichenfolge haben, sollten Sie in Betracht ziehen, dass Sie eine Art Zusammenfassung im Voraus berechnen und in einer separaten Spalte speichern können.
Für URLs können Sie beispielsweise die Domain separat speichern. Und wenn Sie tatsächlich die Domain benötigen, verwenden Sie einfach diese Spalte, während die URLs liegen bleiben und Sie sie nicht einmal berühren werden.
Lassen Sie uns sehen, welche Unterschiede entstehen. In ClickHouse gibt es eine spezialisierte Funktion, die die Domain berechnet. Sie ist sehr schnell, wir haben sie optimiert. Und um ehrlich zu sein, entspricht sie nicht einmal dem RFC, aber dennoch berechnet sie alles, was wir benötigen.
In einem Fall werden wir einfach die URLs abrufen und die Domain berechnen. Das ergibt 166 Millisekunden. Wenn wir jedoch die fertige Domain nehmen, kommen wir nur auf 67 Millisekunden, das heißt, fast dreimal schneller. Und zwar schneller nicht, weil wir irgendwelche Berechnungen durchführen müssen, sondern weil wir weniger Daten lesen.
Warum hat ein langsamerer Abfrage jedoch eine höhere Geschwindigkeit in Gigabyte pro Sekunde? Weil er mehr Gigabyte liest. Das sind völlig überflüssige Daten. Die Abfrage scheint schneller zu sein, wird aber über einen längeren Zeitraum ausgeführt.
Wenn man sich das Volumen der Daten auf der Festplatte ansieht, stellt sich heraus, dass die URL 126 Megabyte und die Domain nur 5 Megabyte beträgt. Das macht in der Tat 25-mal weniger. Dennoch wird die Abfrage nur 4-mal schneller ausgeführt. Aber das liegt daran, dass die Daten heiß sind. Wären sie kalt, wäre es sicherlich 25-mal schneller aufgrund der Festplatten-E/A.
Wenn man übrigens abschätzt, wie viel kleiner die Domain im Vergleich zur URL ist, ergibt sich ein Faktor von etwa 4. Aber warum belegen die Daten auf der Festplatte 25-mal weniger Platz? Wegen der Kompression. Sowohl die URL als auch die Domain werden komprimiert. Oft enthält die URL jedoch eine Menge Müll.

Und natürlich sollte man die richtigen Datentypen verwenden, die speziell für die erforderlichen Werte oder die passenden vorgesehen sind. Wenn Sie IPv4 verwenden, speichern Sie UInt32*. Wenn IPv6, dann FixedString(16), denn eine IPv6-Adresse ist 128 Bit, das heißt, speichern Sie sie direkt im Binärformat.
Was ist, wenn Sie manchmal IPv4-Adressen und manchmal IPv6-Adressen haben? Ja, man kann beide speichern. Eine Spalte für IPv4, die andere für IPv6. Natürlich gibt es die Möglichkeit, IPv4 in IPv6 abzubilden. Das wird auch funktionieren, aber wenn Sie in Ihren Abfragen oft genau die IPv4-Adresse benötigen, wäre es gut, sie in eine separate Spalte zu stecken.
* Jetzt gibt es in ClickHouse spezielle Datentypen für IPv4 und IPv6, die Daten ebenso effizient wie Zahlen speichern, sie jedoch auch so bequem darstellen wie Strings.

Es ist auch wichtig zu beachten, dass es sinnvoll ist, die Daten im Voraus vorzubereiten. Zum Beispiel, wenn Ihnen rohe Protokolle vorliegen. Und vielleicht sollten Sie sie nicht sofort in ClickHouse einspeisen, obwohl es verlockend ist, nichts zu tun und alles zu funktionieren. Aber es ist trotzdem besser, die Berechnungen durchzuführen, die möglich sind.
Zum Beispiel die Version des Browsers. In einer benachbarten Abteilung, auf die ich nicht zeigen möchte, wird die Browserversion so gespeichert, d. h. als Zeichenkette: 12.3. Und dann, um einen Bericht zu erstellen, nehmen sie diese Zeichenkette, teilen sie durch ein Array und dann durch das erste Element des Arrays. Natürlich wird alles langsamer. Ich habe gefragt, warum sie das so machen. Sie haben mir geantwortet, dass sie vorzeitige Optimierung nicht mögen. Aber ich mag vorzeitige Pessimierung nicht.
In diesem Fall ist es also richtiger, in 4 Spalten zu unterteilen. Fürchten Sie sich nicht, denn das ist ClickHouse. ClickHouse ist eine spaltenbasierte Datenbank. Je mehr sorgfältig ausgearbeitete kleine Spalten, desto besser. Wenn es 5 BrowserVersionen gibt, machen Sie 5 Spalten. Das ist in Ordnung.

Betrachten wir nun, was zu tun ist, wenn Sie viele sehr lange Zeichenfolgen und sehr lange Arrays haben. Diese müssen überhaupt nicht in ClickHouse gespeichert werden. Stattdessen können Sie in ClickHouse nur eine Art Identifikator speichern. Und diese langen Strings sollten in ein anderes System übertragen werden.
Zum Beispiel gibt es in einem unserer Analysetools einige Ereignisparameter. Wenn viele Parameter für Ereignisse ankommen, speichern wir einfach die ersten 512, die wir finden, denn 512 sind nicht zu schade.

Wenn Sie sich nicht über Ihre Datentypen entscheiden können, können Sie auch die Daten in ClickHouse schreiben, aber in eine temporäre Tabelle des Typs Log, die speziell für temporäre Daten ausgelegt ist. Danach können Sie analysieren, wie Ihre Verteilung von Werten aussieht, was es gibt und die richtigen Typen erstellen.
* Derzeit gibt es in ClickHouse den Datentyp der es ermöglicht, Strings effizient mit geringerem Aufwand zu speichern.

Betrachten wir nun einen weiteren interessanten Fall. Manchmal funktioniert bei den Leuten alles irgendwie merkwürdig. Ich gehe hinein und sehe Folgendes. Und sofort kommt die Vorstellung, dass dies von einem sehr erfahrenen, klugen Administrator gemacht wurde, der viel Erfahrung mit der Konfiguration von MySQL Version 3.23 hat.
Hier sehen wir tausend Tabellen, in denen jeweils der Rest der Division von unklar was durch tausend gespeichert ist.
Im Prinzip respektiere ich die Erfahrungen anderer und verstehe auch, durch welche Leiden diese Erfahrungen erworben werden können.

Die Gründe sind mehr oder weniger klar. Es sind alte Stereotypen, die sich bei der Arbeit mit anderen Systemen angesammelt haben könnten. Zum Beispiel gibt es in MyISAM-Tabellen keinen clusternden Primärschlüssel. Und diese Art der Datenaufteilung kann ein verzweifelter Versuch sein, die gleiche Funktionalität zu erreichen.
Ein anderer Grund ist, dass es schwierig ist, große Tabellen mit Operationen wie ALTER zu bearbeiten. Alles wird blockiert. Obwohl dieses Problem in modernen Versionen von MySQL nicht mehr so gravierend ist.
Oder zum Beispiel Mikroscharding, aber dazu mehr später.

In ClickHouse muss man das nicht tun, denn erstens ist der Primärschlüssel ein Cluster, und die Daten sind nach dem Primärschlüssel sortiert.
Manchmal werde ich gefragt: "Wie verändert sich die Leistung von Bereichsanfragen in ClickHouse mit der Größe der Tabelle?" Ich sage, dass sie sich gar nicht verändert. Zum Beispiel haben Sie eine Tabelle mit einer Milliarde Zeilen und lesen einen Bereich von einer Million Zeilen. Alles ist in Ordnung. Wenn die Tabelle eine Billion Zeilen hat und Sie eine Million Zeilen lesen, wird es nahezu dasselbe sein.
Zweitens sind keine manuellen Partitionierungen erforderlich. Wenn Sie schauen, was im Dateisystem dort ist, sehen Sie, dass eine Tabelle eine recht ernsthafte Angelegenheit ist. Und dort gibt es etwas wie Partitionen. Das heißt, ClickHouse erledigt alles für Sie, und Sie müssen nicht leiden.

ALTER in ClickHouse ist kostenlos, wenn es sich um ALTER ADD/DROP COLUMN handelt.
Und es ist nicht sinnvoll, kleine Tabellen zu erstellen, denn ob Sie 10 Zeilen oder 10.000 Zeilen in Ihrer Tabelle haben, spielt absolut keine Rolle. ClickHouse ist ein System, das den Durchsatz optimiert und nicht die Latenz, sodass es keinen Sinn macht, 10 Zeilen zu verarbeiten.

Es ist richtig, eine große Tabelle zu verwenden. Befreien Sie sich von alten Stereotypen, alles wird gut.
Als Bonus haben wir in der letzten Version die Möglichkeit eingeführt, einen willkürlichen Partitionierungsschlüssel zu erstellen, um Wartungsoperationen an einzelnen Partitionen durchzuführen.
Zum Beispiel benötigen Sie viele kleine Tabellen, zum Beispiel, wenn es notwendig ist, einige Zwischendaten zu verarbeiten, die Ihnen in Chunks geliefert werden, und Sie müssen Transformationen an ihnen durchführen, bevor Sie sie in die endgültige Tabelle schreiben. Für diesen Fall gibt es einen großartigen Tabellenmotor – StripeLog. Es ist ungefähr wie TinyLog, nur besser.
* Jetzt gibt es in ClickHouse auch .

Ein weiteres Antipattern ist Mikroscharding. Zum Beispiel müssen Sie Daten sharden und Sie haben 5 Server, und morgen wird es 6 Server geben. Und Sie denken darüber nach, wie Sie diese Daten umverteilen können. Stattdessen teilen Sie nicht in 5 Shards auf, sondern in 1.000 Shards. Und dann weisen Sie jeden dieser Mikroschards einem separaten Server zu. Und Sie haben zum Beispiel auf einem Server 200 ClickHouse-Instanzen. Separate Instanzen auf unterschiedlichen Ports oder separate Datenbanken.

Aber in ClickHouse ist das nicht sehr gut. Denn selbst eine Instanz von ClickHouse versucht, alle verfügbaren Ressourcen des Servers zu nutzen, um eine Anfrage zu verarbeiten. Das heißt, Sie haben einen Server und dort zum Beispiel 56 CPU-Kerne. Sie führen eine Anfrage aus, die eine Sekunde dauert, und sie wird 56 Kerne nutzen. Wenn Sie dort jedoch 200 ClickHouse-Instanzen auf einem Server platziert haben, werden 10.000 Threads gestartet. Insgesamt wird alles sehr schlecht sein.
Ein weiterer Grund ist, dass die Verteilung der Arbeit auf diese Instanzen ungleichmäßig sein wird. Einige werden früher fertig, andere später. Wenn das alles in einer Instanz passieren würde, würde ClickHouse selbst herausfinden, wie man die Daten korrekt auf die Threads verteilt.
Und ein weiterer Grund ist, dass es inter-prozessorale Kommunikation über TCP geben wird. Die Daten müssen serialisiert und deserialisiert werden, und das ist eine enorme Anzahl von Mikroschards. Es wird einfach ineffizient funktionieren.

Ein weiteres Antipattern, obwohl es schwierig ist, es als solches zu bezeichnen. Das ist eine große Anzahl an Pre-Aggregationen.
Im Allgemeinen ist Pre-Aggregation gut. Sie hatten eine Milliarde Zeilen, Sie haben sie aggregiert und es sind 1.000 Zeilen geworden, und jetzt wird die Anfrage sofort ausgeführt. Alles wunderbar. So kann man das machen. Und dafür gibt es sogar in ClickHouse einen speziellen Tabellentyp, den AggregatingMergeTree, der inkrementelle Aggregation während des Einfügens von Daten durchführt.
Es gibt jedoch Fälle, in denen Sie denken, dass wir die Daten so aggregieren werden und dann noch so aggregieren. In einer benachbarten Abteilung, von der ich nicht sprechen möchte, verwenden sie die SummingMergeTree-Tabellen zur Aggregation nach dem Primärschlüssel, und als Primärschlüssel verwenden sie etwa 20 verschiedene Spalten. Ich habe zur Sicherheit einige Spaltennamen zur Tarnung geändert, aber ungefähr so ist es.

Und es treten solche Probleme auf. Erstens, das Datenvolumen verringert sich nicht drastisch. Zum Beispiel reduziert es sich um das Dreifache. Ein Dreifaches wäre ein guter Preis, um sich unbegrenzte Möglichkeiten für Analysen zu ermöglichen, die entstehen, wenn Ihre Daten nicht aggregiert sind. Wenn die Daten aggregiert sind, erhalten Sie anstelle von Analysen lediglich mickrige Statistiken.
Was besonders nervt? Dass diese Leute aus der benachbarten Abteilung manchmal kommen und darum bitten, noch eine Spalte zum Primärschlüssel hinzuzufügen. D. h. wir haben die Daten so aggregiert, wollen jetzt aber etwas mehr. Aber in ClickHouse gibt es kein Ändern des Primärschlüssels. Deshalb muss man irgendwelche Skripte in C++ schreiben. Und ich mag keine Skripte, selbst wenn sie in C++ sind.
Wenn man sich ansieht, wofür ClickHouse entwickelt wurde, sind nicht aggregierte Daten genau das Szenario, für das es geboren wurde. Wenn Sie ClickHouse für nicht aggregierte Daten verwenden, machen Sie alles richtig. Wenn Sie aggregieren, ist das manchmal verzeihlich.

Ein weiterer interessanter Fall sind Abfragen in einer Endlosschleife. Manchmal gehe ich auf einen Produktionsserver und sehe mir die Prozessliste an. Und jedes Mal stelle ich fest, dass etwas Schreckliches passiert.
Zum Beispiel so etwas. Hier wird sofort klar, dass man alles in einer Abfrage hätte ausführen können. Schreiben Sie einfach dort url in und die Liste.

Warum sind so viele solcher Abfragen in einer Endlosschleife schlecht? Wenn der Index nicht verwendet wird, haben Sie viele Durchläufe über dieselben Daten. Aber wenn der Index verwendet wird, zum Beispiel, wenn Sie einen Primärschlüssel nach ru haben und Sie schreiben url = irgendetwas. Und Sie denken, dass nur dieser eine url genau aus der Tabelle gelesen wird, wird alles in Ordnung sein. Aber in Wirklichkeit ist das nicht der Fall. Denn ClickHouse arbeitet alles in Bündeln ab.
Wenn er einen bestimmten Datenbereich lesen muss, liest er ein wenig mehr, da der Index in ClickHouse spärlich ist. Dieser Index ermöglicht es nicht, eine individuelle Zeile in der Tabelle zu finden, sondern nur einen bestimmten Bereich. Die Daten werden in Blöcken komprimiert. Um eine Zeile zu lesen, muss man einen ganzen Block nehmen und ihn dekomprimieren. Wenn Sie viele Abfragen durchführen, gibt es viele Überschneidungen, und eine Menge Arbeit wird immer wiederholt.

Und als Bonus kann man bemerken, dass man in ClickHouse keine Angst haben muss, selbst Megabyte und sogar Hunderte von Megabyte in die IN-Klausel zu übergeben. Ich erinnere mich aus unserer Praxis, dass wenn wir in MySQL eine Menge Werte in die IN-Klausel übergeben, zum Beispiel 100 Megabyte irgendwelcher Zahlen, dann schluckt MySQL 10 Gigabyte Speicher und sonst passiert nichts, alles funktioniert schlecht.
Und das Zweite ist, dass in ClickHouse, wenn Ihre Abfragen den Index nutzen, es immer nicht langsamer ist als ein Full Scan, d.h. wenn fast die gesamte Tabelle gelesen werden muss, wird es sequenziell durchgeführt und die gesamte Tabelle gelesen. Insgesamt kümmert sich ClickHouse selbst darum.
Dennoch gibt es einige Schwierigkeiten. Zum Beispiel nutzt die IN-Klausel mit einer Unterabfrage den Index nicht. Aber das ist unser Problem und wir müssen das beheben. Es gibt hier nichts Fundamentales. Wir werden es reparieren.
Und eine weitere interessante Sache ist, dass wenn Sie eine sehr lange Abfrage haben und die Verarbeitung der Abfragen verteilt erfolgt, dann wird diese sehr lange Abfrage ohne Kompression an jeden Server gesendet. Zum Beispiel 100 Megabyte und 500 Server. Entsprechend werden über das Netzwerk 50 Gigabyte übertragen. Es wird übertragen und dann wird alles erfolgreich ausgeführt.
* benutzt bereits; alles repariert, wie versprochen.

Und ein recht häufiger Fall ist, wenn Abfragen aus APIs kommen. Zum Beispiel, Sie haben einen eigenen Service erstellt. Und wenn Ihr Service jemandem wichtig ist, dann haben Sie eine API geöffnet und sehen bereits nach zwei Tagen, dass etwas Unverständliches passiert. Alles ist überlastet und es kommen schreckliche Abfragen, die niemals hätten kommen sollen.
Und die Lösung ist einfach. Wenn Sie eine API geöffnet haben, müssen Sie sie kürzen. Zum Beispiel Quoten einführen. Es gibt keine anderen vernünftigen Optionen. Andernfalls wird sofort ein Skript geschrieben und es gibt Probleme.
Und ClickHouse bietet eine spezielle Möglichkeit – die Zählung von Quoten. Dabei kann man seinen eigenen Quoten-Schlüssel übergeben. Das kann zum Beispiel eine interne Benutzer-ID sein. Und die Quoten werden unabhängig für jeden von ihnen gezählt.

Jetzt noch eine interessante Sache. Das ist die Replikation mit manueller Steuerung.
Ich kenne viele Fälle, in denen, trotz der integrierten Unterstützung für Replikation in ClickHouse, die Leute ClickHouse manuell replizieren.
Welches Prinzip steckt dahinter? Sie haben eine Datenverarbeitungs-Pipeline. Und diese funktioniert unabhängig, zum Beispiel in verschiedenen Rechenzentren. Sie schreiben die gleichen Daten auf die gleiche Art in ClickHouse. Allerdings zeigt die Praxis, dass die Daten aufgrund bestimmter Besonderheiten in Ihrem Code dennoch auseinanderdriften werden. Ich hoffe, in Ihrem nicht.
Und gelegentlich müssen Sie trotzdem manuell synchronisieren. Zum Beispiel führen die Administratoren einmal im Monat ein rsync durch.
In der Tat ist es viel einfacher, die in ClickHouse integrierte Replikation zu verwenden. Aber es kann einige Vorbehalte geben, denn dafür müssen Sie ZooKeeper verwenden. Ich will nichts Schlechtes über ZooKeeper sagen, grundsätzlich ist das System funktional, aber es kommt vor, dass Menschen es aufgrund von Java-Phobie nicht verwenden, denn ClickHouse ist ein gutes System, das in C++ geschrieben ist, das man nutzen kann und das hervorragend funktioniert. Aber ZooKeeper ist in Java. Und man hat irgendwie nicht das Bedürfnis, sich das anzusehen, aber dann können Sie die Replikation mit manueller Steuerung verwenden.

ClickHouse ist ein praktisches System. Es berücksichtigt Ihre Bedürfnisse. Wenn Sie Replikation mit manueller Steuerung haben, können Sie eine verteilte Tabelle erstellen, die auf Ihre manuellen Replikate schaut und selbst zwischen diesen einen Failover durchführt. Es gibt sogar eine spezielle Option, die es ermöglicht, Flaps zu vermeiden, selbst wenn Ihre Replikate systematisch auseinandergehen.

Es können Probleme auftreten, wenn Sie primitive Table Engines verwenden. ClickHouse ist eine Art Baukasten mit einer Vielzahl verschiedener Tabellen-Engines. Für alle ernsten Fälle sollte, wie in der Dokumentation angegeben, die MergeTree-Familie verwendet werden. Alle anderen sind eher für spezielle Fälle oder Tests gedacht.
In der MergeTree-Tabelle ist es nicht unbedingt erforderlich, dass Sie ein Datum und eine Uhrzeit haben. Sie können sie dennoch verwenden. Wenn es kein Datum und keine Uhrzeit gibt, geben Sie an, dass das Standarddatum das Jahr 2000 ist. Das wird funktionieren und benötigt keine Ressourcen.
In der neuen Serverversion können Sie sogar angeben, dass Sie eine benutzerdefinierte Partitionierung ohne Partitionsschlüssel haben möchten. Es bleibt dasselbe.

Andererseits können primitive Tabellensysteme verwendet werden. Zum Beispiel können Sie Daten einmal importieren und dann spielen, drehen und löschen. Sie können Log verwenden.
Oder die Speicherung kleiner Datenmengen zur Zwischenverarbeitung – das ist StripeLog oder TinyLog.
Memory kann verwendet werden, wenn Sie eine kleine Datenmenge haben und einfach etwas im RAM bewegen möchten.

ClickHouse mag keine über-normalisierten Daten.
Hier ist ein typisches Beispiel. Es gibt eine riesige Menge an URLs. Sie haben sie in eine benachbarte Tabelle gesteckt. Und dann wollten Sie damit JOIN machen, aber das funktioniert normalerweise nicht, da ClickHouse nur Hash JOIN unterstützt. Wenn nicht genügend RAM für die vielen Daten vorhanden ist, die verbunden werden müssen, kann der JOIN nicht ausgeführt werden*.
Wenn die Daten eine hohe Kardinalität haben, machen Sie sich keine Sorgen, halten Sie sie in denormalisierter Form, URLs direkt inplace in der Haupttabelle.
* Aber jetzt gibt es in ClickHouse auch Merge JOIN, und er funktioniert unter Bedingungen, wenn die Zwischendaten nicht im RAM Platz finden. Aber das ist ineffizient, und die Empfehlung bleibt bestehen.

Hier sind noch ein paar Beispiele, aber ich zweifle bereits, ob sie antipattern sind oder nicht.
In ClickHouse gibt es einen bekannten Nachteil. Er kann keine Updates durchführen*. In gewissem Sinne ist das sogar gut. Wenn Sie wichtige Daten haben, zum Beispiel Buchhaltungsdaten, kann niemand sie senden, weil es keine Updates gibt.
* Unterstützung für Updates und Deletes im Batch-Modus wurde schon lange hinzugefügt.
Aber es gibt einige spezielle Methoden, die es ermöglichen, Updates gewissermaßen im Hintergrund durchzuführen. Zum Beispiel Tabellen vom Typ ReplaceMergeTree. Sie führen Updates während der Hintergrund-Merges durch. Sie können dies mit optimize table erzwingen. Aber machen Sie das nicht zu oft, denn das führt zur vollständigen Neuschreibung der Partition.
Verteilte JOINs in ClickHouse werden vom Query-Planer ebenfalls schlecht verarbeitet.
Schlecht, aber manchmal in Ordnung.
Die Verwendung von ClickHouse nur, um Daten über select* zurückzulesen.
Ich würde nicht empfehlen, ClickHouse für umfangreiche Berechnungen zu verwenden. Aber so ganz stimmt das nicht, denn wir gehen bereits von dieser Empfehlung ab. Und kürzlich haben wir die Möglichkeit hinzugefügt, Machine-Learning-Modelle in ClickHouse anzuwenden – Catboost. Das bereitet mir Sorgen, denn ich denke: "Wie schrecklich. Wie viele Taktzyklen pro Byte sind das!" Es tut mir leid, Taktrate für Bytes zu verschwenden.

Aber keine Angst, installieren Sie ClickHouse, alles wird gut. Wenn Sie Fragen haben, haben wir eine Community. Übrigens, die Community sind Sie. Und wenn Sie irgendwelche Probleme haben, können Sie zumindest in unseren Chat kommen, und ich hoffe, dass Ihnen geholfen wird.
Fragen
Danke für die Präsentation! Wo kann ich mich über einen ClickHouse-Absturz beschweren?
Sie können sich gerne direkt jetzt an mich wenden.
Ich habe kürzlich angefangen, ClickHouse zu verwenden. Ich habe sofort die CLI-Oberfläche zum Absturz gebracht.
Sie haben Glück.
Kurze Zeit später habe ich den Server mit einer kleinen SELECT-Anfrage zum Absturz gebracht.
Sie haben Talent.
Ich habe einen Bug auf GitHub gemeldet, aber er wurde ignoriert.
Schauen wir mal.
Alexey hat mich mit einem Trick dazu gebracht, einen Vortrag zu halten, indem er versprochen hat zu erklären, wie ihr die Daten intern komprimiert.
Ganz einfach.
Das habe ich auch schon gestern verstanden. Mehr Konkretes.
Es gibt keine fiesen Tricks. Es handelt sich einfach um Blockkompression. Standardmäßig wird LZ4 verwendet, Sie können ZSTD aktivieren*. Die Blöcke sind von 64 Kilobyte bis 1 Megabyte.
* Es gibt auch Unterstützung für spezialisierte Kompressionscodecs, die in Kombination mit anderen Algorithmen verwendet werden können.
Sind die Daten in den Blöcken einfach rohe Daten?
Nicht ganz roh. Dort sind Arrays. Wenn Sie eine numerische Spalte haben, sind die Zahlen in einem Array hintereinander angeordnet.
Verstanden.
Alexey, das Beispiel mit uniqExact über die IP-Adressen, d. h. dass uniqExact über Strings länger braucht als über Zahlen usw. Und was ist, wenn wir einen Trick anwenden und beim Auslesen casten? Das heißt, Sie haben anscheinend gesagt, dass es auf der Festplatte nicht so viel Unterschied gibt. Wenn wir Strings von der Festplatte lesen und casten, sind die Aggregationen dann schneller oder nicht? Oder gewinnen wir hier dennoch nur geringfügig? Mir scheint, dass Sie das getestet haben, aber aus irgendeinem Grund nicht im Benchmark angegeben haben.
Ich denke, dass es langsamer sein wird als ohne Casting. In diesem Fall muss die IP-Adresse aus der Zeichenkette geparsed werden. Natürlich ist in ClickHouse auch das Parsen von IP-Adressen optimiert. Wir haben uns sehr angestrengt, aber die Zahlen sind in Zehntausenderform geschrieben. Sehr unpraktisch. Auf der anderen Seite wird die Funktion uniqExact bei Zeichenfolgen langsamer arbeiten, nicht nur weil es Zeichenfolgen sind, sondern auch weil eine andere Algorithmusspezialisierung gewählt wird. Zeichenfolgen werden einfach anders verarbeitet.
Und wenn wir einen primitiveren Datentyp nehmen? Zum Beispiel haben wir die Benutzer-ID, die wir im Input haben, als Zeichenkette gespeichert und dann gecastet. Wird es dann besser oder schlechter?
Ich habe Zweifel. Ich denke sogar, dass es trauriger sein wird, denn das Parsen von Zahlen ist schließlich ein ernsthaftes Problem. Mir scheint, dass ein Kollege sogar einen Vortrag über die Schwierigkeiten beim Parsen von Zahlen in Zehntausenderform gehalten hat, oder vielleicht auch nicht.
Alexey, vielen Dank für den Vortrag! Und danke auch für ClickHouse! Ich habe eine Frage zu den Plänen. Gibt es Pläne für eine Funktion, um Wörterbücher nicht vollständig zu aktualisieren?
Das heißt, partielle Neulandung?
Ja, genau. So eine Möglichkeit, ein MySQL-Feld anzugeben, d. h. nachträglich zu aktualisieren, sodass nur diese Daten geladen werden, wenn das Wörterbuch sehr groß ist.
Eine sehr interessante Funktion. Und ich glaube, jemand hat dies in unserem Chat vorgeschlagen. Vielleicht waren Sie das sogar.
Ich glaube nicht, dass ich das war.
Großartig, jetzt ergibt sich, dass es zwei Anfragen gibt. Und wir können in Ruhe anfangen, daran zu arbeiten. Aber ich möchte Sie sofort warnen, dass diese Funktion ziemlich einfach umzusetzen ist. Das heißt, theoretisch muss man einfach die Versionsnummer in die Tabelle schreiben und dann schreiben: Version kleiner als diese. Das bedeutet, dass wir wahrscheinlich vorschlagen werden, dies Enthusiasten zu überlassen. Sind Sie ein Enthusiast?
Ja, aber leider nicht in C++.
Können Ihre Kollegen in C++ programmieren?
Ich werde jemanden finden.
Ausgezeichnet*.
* Die Möglichkeit wurde zwei Monate nach dem Vortrag hinzugefügt – sie wurde vom Autor der Frage entwickelt und gesendet. .
Danke!
Hallo! Vielen Dank für den Vortrag! Sie haben erwähnt, dass ClickHouse alle verfügbaren Ressourcen sehr gut nutzt. Der Referent, der neben Luxoft sprach, berichtete von seiner Lösung für die Post Russland. Er sagte, dass ihnen ClickHouse sehr gefallen hat, aber sie es nicht anstelle ihres Hauptkonkurrenten verwendet haben, gerade weil es die gesamte CPU-Auslastung beansprucht hat. Und sie konnten es nicht in ihre Architektur, in ihren ZooKeeper mit Docker-Containern integrieren. Gibt es eine Möglichkeit, ClickHouse irgendwie zu begrenzen, damit es nicht alles verbraucht, was ihm zur Verfügung steht?
Ja, das ist möglich und sehr einfach. Wenn Sie möchten, dass weniger Kerne verwendet werden, schreiben Sie einfach set max_threads = 1. Und das war's, er wird die Anfrage auf einem Kern ausführen. Außerdem können verschiedene Benutzer unterschiedliche Einstellungen festlegen. Es gibt also keine Probleme. Und sagen Sie den Kollegen von Luxoft, dass es nicht gut ist, dass sie diese Einstellung in der Dokumentation nicht gefunden haben.
Alexei, hallo! Ich würde gerne eine Frage stellen. Ich habe schon mehrmals gehört, dass viele ClickHouse als Log-Speicher verwenden. In Ihrem Vortrag haben Sie gesagt, dass man das nicht tun sollte, d. h. dass man keine langen Zeilen speichern sollte. Was halten Sie davon?
Erstens sind Logs in der Regel keine langen Zeilen. Es gibt natürlich Ausnahmen. Zum Beispiel, wenn ein Dienst, der in Java geschrieben ist, eine Ausnahme auslöst, wird sie protokolliert. Und das in einer endlosen Schleife, bis der Speicherplatz auf der Festplatte erschöpft ist. Die Lösung ist sehr einfach. Wenn die Zeilen sehr lang sind, schneiden Sie sie ab. Und was bedeutet lang? Dutzende Kilobyte sind schlecht*.
* In den neuesten Versionen von ClickHouse ist "adaptive Granularität des Indexes" aktiviert, was das Problem des Speicherns langer Zeilen größtenteils löst.
Ist ein Kilobyte normal?
Normal.
Hallo! Vielen Dank für den Vortrag! Ich habe bereits in der Chat gefragt, weiß aber nicht, ob ich eine Antwort erhalten habe. Ist geplant, den WITH-Abschnitt ähnlich wie CTE zu erweitern?
Im Moment nicht. Der WITH-Abschnitt ist bei uns etwas unseriös. Er ist für uns nur ein kleines Feature.
Ich verstehe. Vielen Dank!
Vielen Dank für den Vortrag! Sehr interessant! Eine allgemeine Frage. Ist geplant, vielleicht eine Art Schnittstelle für die Datenlöschung zu schaffen?
Unbedingt. Das ist unsere erste Aufgabe in unserer Warteschlange. Wir haben jetzt aktiv darüber nachgedacht, wie wir alles richtig machen können. Und es ist an der Zeit, mit dem Tippen zu beginnen*.
* Haben die Tasten auf der Tastatur gedrückt und alles erledigt.
Wird sich das irgendwie auf die Systemleistung auswirken oder nicht? Wird das Einfügen genauso schnell sein wie jetzt?
Vielleicht werden die deletes, die updates sehr schwer sein, aber das wird die Leistung der selects und der inserts nicht beeinträchtigen.
Und noch eine kleine Frage. Bei der Präsentation sprachen Sie über den Primärschlüssel. Haben wir also eine Partitionierung, die standardmäßig monatlich ist, richtig? Und wenn wir einen Datumsbereich festlegen, der in einen Monat fällt, wird nur diese Partition gelesen, korrekt?
Ja.
Eine solche Frage. Wenn wir keinen Primärschlüssel festlegen können, ist es dann richtig, ihn nach dem Feld "Datum" zu erstellen, um im Hintergrund eine geringere Umstrukturierung dieser Daten zu gewährleisten, damit sie geordneter sind? Wenn Sie keine Bereichsanfragen haben und keinen Primärschlüssel wählen können, sollten Sie dann das Datum in den Primärschlüssel aufnehmen?
Ja.
Vielleicht macht es Sinn, ein Feld im Primärschlüssel aufzunehmen, bei dem die Daten besser komprimiert werden, wenn sie nach diesem Feld sortiert sind. Zum Beispiel die Benutzer-ID. Ein Benutzer besucht beispielsweise immer dieselbe Website. In diesem Fall legen Sie die Benutzer-ID und die Uhrzeit ab. Dann werden Ihre Daten besser komprimiert. Was das Datum betrifft, wenn Sie wirklich keine und niemals Bereichsanfragen nach Datumsangaben haben, dann müssen Sie das Datum nicht im Primärschlüssel ablegen.
Gut, vielen Dank!
Quelle: habr.com
