Die Ausführung von zwei identischen Anforderungen, aber das Schlüsselwort DISTINCT führt zu unerwarteten Ergebnissen. Ohne das Schlüsselwort ist das Ergebnis in Ordnung, aber mit DISTINCT sieht es so aus, als ob die Where-Klausel ignoriert wird. Warum?
Cqlsh-Version:
%Vor%Tabelle berücksichtigt:
%Vor%Tabelleninhalt:
%Vor%Anfrage1: Anfrage ohne DISTINCT
%Vor%Anfrage2: Gleiche Anfrage mit DISTINCT
%Vor% EDIT 1
Hier ist ein Zusammenhang.
Diese Tabelle "Ereignisse" unterliegt einer Vielzahl von Schreibvorgängen, sie erhält ca. 1k Einfügungen pro Sekunde und ich habe ein Batch-Skript, das diese Ereignisse alle 5 Minuten überprüft.
Dieses Stapelscript hat 2 Bedürfnisse:
1- Holen Sie sich alle Benutzer-IDs, die in den letzten 5 Minuten aktiv waren (d. H. Jede Benutzer-ID in den Ereignissen der letzten 5 Minuten)
2- Holen Sie sich alle Ereignisse zu diesen Benutzer-IDs (nicht nur für die letzten 5 Minuten)
Ich hatte zwei verschiedene Tabellen, um damit umzugehen. Eine Tabelle "activeusers" für die erste Anfrage und die "events" -Tabelle wie ich sie hier für die zweite Anfrage beschrieben habe. Mein Problem damit ist nur, dass es von meinem Server verlangt, in zwei verschiedene Tabellen zu schreiben, wenn es ein Ereignis empfängt. Also habe ich das nur mit der Ereignistabelle versucht.
Das passiert so, weil in Cassandra CQL DISTINCT
nur die Partitions (Zeilen) -Schlüssel Ihrer Tabelle (Spaltenfamilie) zurückgibt, die eindeutig sein müssen. Daher kann die Klausel WHERE
nur auf Partitionsschlüsseln angewendet werden, wenn sie mit DISTINCT
verwendet wird (was in Ihrem Fall nicht besonders nützlich ist). Wenn Sie DISTINCT
out verwenden, kann WHERE
verwendet werden, um die Cluster (Spalten) -Schlüssel innerhalb jedes Partitionsschlüssels auszuwerten (allerdings mit ALLOW FILTERING
).
Ich fühle mich gezwungen zu erwähnen, dass ALLOW FILTERING
nicht etwas ist, was Sie viel tun sollten ... und definitiv nicht in der Produktion. Wenn diese Abfrage eine ist, die Sie häufig ausführen müssen (Abfragen von Ereignissen für userids
nach einem bestimmten timestamp
), würde ich vorschlagen, Ihre Daten stattdessen nach event_type
zu partitionieren:
Dann können Sie diese Abfrage ohne ALLOW FILTERING
ausführen.
Ohne etwas über Ihre Anwendung oder Ihren Anwendungsfall zu wissen, kann dies für Sie nützlich sein oder auch nicht. Aber betrachten Sie es als ein Beispiel, und als ein Hinweis, dass es möglicherweise einen besseren Weg gibt, Ihr Modell zu bauen, um Ihr Anfrage-Muster (s) zu befriedigen. Sehen Sie sich Patrick McFadins Artikel über die Modellierung von Zeitreihen für weitere Ideen an Modell für dieses Problem.
Wie von Aaron erläutert, können Sie das Schlüsselwort DISTINCT nur nach Partitionsschlüsseln filtern. Der Grund dafür ist der Algorithmus hinter DISTINCT-Abfragen und die Art und Weise, wie Cassandra die Daten auf dem Datenträger / Speicher speichert.
Um das zu verstehen, mache ich eine Analogie:
Cassandra speichert die Informationen ähnlich wie ein Buchindex. Wenn Sie ein Kapitel mit dem Namen "Mein drittes Kapitel" suchen, müssen Sie nur die erste Ebene des Indexes suchen, so dass Sie nur eine iterative Suche in einem relativ kleinen Satz durchführen müssen. Wenn Sie jedoch ein Unterkapitel mit dem Namen "Mein viertes Unterkapitel" suchen, das zu "Mein zweites Kapitel" gehört, müssen Sie 2 iterative Suchen in 2 verschiedenen Sätzen durchführen, vorausgesetzt, der Index hat mindestens 2 Ebenen. Je tiefer Sie gehen müssen, desto länger kann es dauern (Sie können immer noch Glück haben und finden es sehr schnell, wenn es am Anfang des Indexes ist, aber in dieser Art von Algorithmen müssen Sie für das Mittel- und das Worst-Case-Szenario testen) und je komplexer der Index sein muss.
Cassandra macht etwas ähnliches: Schlüsselraum - & gt; Tabelle - & gt; Partitionsschlüssel - & gt; Clustering-Schlüssel - & gt; Säule Je tiefer Sie gehen müssen, desto mehr Sätze müssen Sie im Speicher haben und es wird länger dauern, bis Sie etwas finden. Der Index, der zum Ausführen von DISTINCT-Abfragen verwendet wird, kann sogar nur Sätze bis zur Partitionsschlüsselebene enthalten und somit nur nach Partitionsschlüsseln suchen.
Sie müssen wissen, dass die Suche in einem Kapitel mit einem Unterkapitel namens "Mein zweites Unterkapitel" (was wäre die Analogie zu Ihrer Anfrage) immer noch 2 Ebenen tiefer Index und 2 Ebenen iterative Suche erfordert.
>Wenn sie sich entscheiden, DISTINCT bei Clustering-Schlüsseln zu unterstützen, wäre Ihre Anfrage in Ordnung. In der Zwischenzeit müssen Sie sie in der Anwendung filtern, wahrscheinlich indem Sie einen eingebauten Typ namens set oder etwas ähnliches verwenden, der die wiederholten Werte selbst behandelt.
Auch die von Aaron vorgeschlagene Lösung (die Benutzer-ID als Cluster-Schlüssel nach dem Zeitstempel verwendend), verwendet weder dieser (Filterung auf der Client-Seite) noch den schnellen DISTINCT-Mechanismus. Sein Vorschlag erfordert keine clientseitige Filterung, da er dies bereits für Sie erledigt, aber zwei Hauptnachteile bietet: Es bietet keine Abwärtskompatibilität, da Sie die Tabelle neu erstellen müssen und einen konstanten Partitionsschlüssel verwenden müssen Cassandra, um diese Daten unter seinen Knoten zu verteilen. Denken Sie daran, dass jeder Wert des gleichen Partitionsschlüssels im selben Knoten gespeichert wird.