SELECT DISTINCT cql ignore clause where
L'exécution de deux demandes identiques, mais le mot-clé DISTINCT donne des résultats inattendus. Sans le mot clé, le résultat est ok, mais DISTINCTS, il ressemble à la clause where est ignoré. Pourquoi ?
Cqlsh version:
Connected to Test Cluster at localhost:9160.
[cqlsh 4.1.1 | Cassandra 2.0.6 | CQL spec 3.1.1 | Thrift protocol 19.39.0]
Table considéré:
DESCRIBE TABLE events;
CREATE TABLE events (
userid uuid,
"timestamp" timestamp,
event_type text,
data text,
PRIMARY KEY (userid, "timestamp", event_type)
) WITH
bloom_filter_fp_chance=0.010000 AND
caching='KEYS_ONLY' AND
comment='' AND
dclocal_read_repair_chance=0.000000 AND
gc_grace_seconds=864000 AND
index_interval=128 AND
read_repair_chance=0.100000 AND
replicate_on_write='true' AND
populate_io_cache_on_flush='false' AND
default_time_to_live=0 AND
speculative_retry='99.0PERCENTILE' AND
memtable_flush_period_in_ms=0 AND
compaction={'class': 'SizeTieredCompactionStrategy'} AND
compression={'sstable_compression': 'LZ4Compressor'};
Du contenu de la Table:
SELECT * FROM events;
userid | timestamp | event_type | data
--------------------------------------+--------------------------+------------+------
aaaaaaaa-be1c-44ab-a0e8-f25cf6064b0e | 1970-01-17 09:06:17+0100 | toto | null
4271a78f-be1c-44ab-a0e8-f25cf6064b0e | 1970-01-17 09:06:17+0100 | toto | null
4271a78f-be1c-44ab-a0e8-f25cf6064b0e | 1970-01-17 09:07:17+0100 | toto | null
4271a78f-be1c-44ab-a0e8-f25cf6064b0e | 1970-01-17 09:08:17+0100 | toto | null
4271a78f-be1c-44ab-a0e8-f25cf6064b0e | 1970-01-17 09:09:17+0100 | toto | null
4271a78f-be1c-44ab-a0e8-f25cf6064b0e | 1970-01-17 09:10:17+0100 | toto | null
(6 rows)
Request1: Demande sans DISTINCTES
SELECT userid FROM events WHERE timestamp > '1970-01-17 09:07:17+0100' ALLOW FILTERING;
userid
--------------------------------------
4271a78f-be1c-44ab-a0e8-f25cf6064b0e
4271a78f-be1c-44ab-a0e8-f25cf6064b0e
4271a78f-be1c-44ab-a0e8-f25cf6064b0e
(3 rows)
Request2: Même demande avec des
SELECT DISTINCT userid FROM events WHERE timestamp > '1970-01-17 09:07:17+0100' ALLOW FILTERING;
userid
--------------------------------------
aaaaaaaa-be1c-44ab-a0e8-f25cf6064b0e
4271a78f-be1c-44ab-a0e8-f25cf6064b0e
(2 rows)
EDIT 1
ici, le contexte est.
Cette table "les événements" est sujet à beaucoup de écrit, il reçoit environ 1k insertions par seconde et j'ai un lot de script qui vérifie ces événements toutes les 5 minutes.
Ce lot script a 2 besoins:
1 - obtenir tous les identifiants qui ont été actifs dans les 5 dernières minutes (j'.e chaque nom d'utilisateur présent dans les événements de ces 5 dernières minutes)
2 - obtenir tous les événements liés à ces identifiants (pas seulement pour les 5 dernières minutes)
J'ai utilisé deux tables différentes pour gérer cela. Une table "activeusers" pour la première demande et les "événements" de la table comme je l'ai décrit ici pour la deuxième demande. Mon problème c'est juste qu'elle a besoin de mon serveur à écrire dans deux tables différentes quand il reçoit un événement. J'ai donc essayé cela en utilisant seulement la table des événements.
timestamp
dans le cadre de la clé composée. Je conseille timeuuid
ici pour prévenir les collisions et d'enregistrement écrase. timestamp
si parfaitement bien à l'extérieur de la clé primaire.Est votre colonne timestamp DESC? Semble que vous avez besoin, il a ordonné qu'.
OriginalL'auteur Diplow | 2014-10-24
Vous devez vous connecter pour publier un commentaire.
Il arrive de cette façon à cause de Cassandra, CQL
DISTINCT
est conçu pour renvoyer uniquement la partition (en ligne) les touches de votre table (colonne de la famille)...qui doit être unique. Par conséquent, laWHERE
clause ne peut fonctionner que sur la partition touches lorsqu'il est utilisé avecDISTINCT
(ce qui, dans votre cas, n'est pas très utile). Si vous prenez leDISTINCT
,WHERE
peut ensuite être utilisé pour évaluer le clustering (colonne) clés à l'intérieur de chaque clé de partition (quoique, avecALLOW FILTERING
).Je me sens obligé de mentionner que
ALLOW FILTERING
n'est pas quelque chose que vous devriez faire tout un tas de...et certainement pas dans la production. Si cette requête est celui dont vous avez besoin pour exécuter souvent (interrogation des événements pouruserids
après un certaintimestamp
) alors je suggère le partitionnement des données parevent_type
à la place:Alors vous serez en mesure d'exécuter cette requête sans
ALLOW FILTERING
.Sans rien connaître au sujet de votre demande ou de cas d'utilisation, qui peut ou peut ne pas être utile pour vous. Mais le considérer comme un exemple, et comme une indication qu'il peut y avoir une meilleure façon de construire votre modèle pour satisfaire votre modèle de requête(s). Découvrez Patrick McFadin de l'article sur timeseries de la modélisation de données pour plus d'idées sur la façon de modèle pour ce problème.
Upvoted réponse solide!
OriginalL'auteur Aaron
Comme l'a expliqué Aaron, lorsque vous utilisez le mot clé DISTINCT, vous ne pouvez filtrer par clés de partition. La raison derrière cela est l'algorithme derrière DISTINCTES des requêtes et de la façon dont Cassandra stocke les données dans le disque/mémoire.
Pour comprendre cela, je vais faire une analogie:
Cassandra stocke les informations similaires à l'index d'un livre. Si vous êtes à la recherche d'un chapitre intitulé "Mon troisième chapitre," vous n'avez qu'à regarder le premier niveau de l'indice pour elle, donc vous avez seulement besoin de faire un processus itératif de recherche dans un ensemble relativement restreint. Toutefois, si vous êtes à la recherche d'un sous-chapitre intitulé "Mon quatrième sous-chapitre" appartenant à "Mon deuxième chapitre," vous aurez à faire 2 itératif de perquisitions dans 2 séries différentes, les deux petits, à condition que l'indice a au moins 2 niveaux. Le plus profond que vous devez aller le plus qu'il peut prendre (vous pouvez être chanceux et trouver très vite s'il est au début de l'index, mais dans ce type d'algorithmes, il faut tester pour la moyenne et le pire des cas) et le plus complexe de l'indice en auront besoin.
Cassandra fait quelque chose de similaire: Espace -> Table> Clé de Partition -> Clé de cluster -> Colonne
Le plus profond que vous devez aller, plus de jeux, vous devez avoir en mémoire et il faudra plus de temps pour trouver quoi que ce soit. L'indice utilisé pour exécuter des requêtes DISTINCTES peuvent même contenir uniquement des listes jusqu'à ce que la clé de partition, en permettant seulement à la recherche de clés de partition.
Vous devez réaliser que la recherche de n'importe quel chapitre a un sous-chapitre calles "Ma deuxième sous-chapitre" (ce qui serait l'analogie de votre requête) nécessite encore 2 niveau profond de l'index et 2 niveau itératif de perquisitions.
Si ils décident de soutien d'utilisation DISTINCTES sur le regroupement des clés, votre requête serait bien. Pendant ce temps, vous aurez à filtrer dans l'application, probablement par l'aide d'un type de jeu ou quelque chose de semblable qui gère les valeurs répétées par lui-même.
Ni la solution proposée par Aaron (en utilisant le nom d'utilisateur comme une clé de clustering après le timestamp) n'est ni l'une (filtrage dans le côté client) utilise l'DISTINCTES mécanisme rapide. Sa proposition ne nécessite pas de filtrage côté client comme elle l'a déjà des poignées pour vous, mais offre deux principaux inconvénients: il n'offre pas de rétro-compatibilité que vous devez recréer la table et utilise une constante clé de partition et donc ne permet pas de Cassandra circulation de ces données entre les nœuds. N'oubliez pas que chaque valeur de la même partition clé est stockée dans le même nœud.
OriginalL'auteur Adirio