Supposons que j'ai une famille de colonnes:
CREATE TABLE update_audit (
scopeid bigint,
formid bigint,
time timestamp,
record_link_id bigint,
ipaddress text,
user_zuid bigint,
value text,
PRIMARY KEY ((scopeid, formid), time)
) WITH CLUSTERING ORDER BY (time DESC)
Avec deux index secondaires, où record_link_id
est une colonne à cardinalité élevée:
CREATE INDEX update_audit_id_idx ON update_audit (record_link_id);
CREATE INDEX update_audit_user_zuid_idx ON update_audit (user_zuid);
Selon mes connaissances Cassandra créera deux familles de colonnes cachées comme ceci:
CREATE TABLE update_audit_id_idx(
record_link_id bigint,
scopeid bigint,
formid bigint,
time timestamp
PRIMARY KEY ((record_link_id), scopeid, formid, time)
);
CREATE TABLE update_audit_user_zuid_idx(
user_zuid bigint,
scopeid bigint,
formid bigint,
time timestamp
PRIMARY KEY ((user_zuid), scopeid, formid, time)
);
Les index secondaires Cassandra sont implémentés comme des index locaux plutôt que d'être distribués comme des tables normales. Chaque nœud ne stocke qu'un index pour les données qu'il stocke.
Considérez la requête suivante:
select * from update_audit where scopeid=35 and formid=78005 and record_link_id=9897;
record_link_id
) affecte ses performances?select * from update_audit where scopeid=35 and formid=78005 and record_link_id=9897;
Comment la requête ci-dessus fonctionnera-t-elle en interne dans Cassandra?
Essentiellement, toutes les données de la partition scopeid=35
et formid=78005
sera retourné, puis filtré par le record_link_id
index. Il recherchera le record_link_id
entrée pour 9897
, et essayez de faire correspondre les entrées qui correspondent aux lignes renvoyées où scopeid=35
et formid=78005
. L'intersection des lignes pour les clés de partition et les clés d'index sera retournée.
Comment l'index de la colonne à cardinalité élevée (record_link_id) affectera les performances de la requête pour la requête ci-dessus?
Les index à cardinalité élevée créent essentiellement une ligne pour (presque) chaque entrée du tableau principal. Les performances sont affectées, car Cassandra est conçu pour effectuer des lectures séquentielles pour les résultats de la requête. Une requête d'index force essentiellement Cassandra pour effectuer aléatoire lit. À mesure que la cardinalité de votre valeur indexée augmente, le temps nécessaire pour trouver la valeur interrogée augmente également.
cassandra va toucher tous les nœuds pour la requête ci-dessus? POURQUOI?
Non. Il ne doit toucher qu'un nœud qui est responsable du scopeid=35
et formid=78005
cloison. De même, les index sont stockés localement, ne contiennent que des entrées valides pour le nœud local.
la création d'index sur des colonnes à cardinalité élevée sera le modèle de données le plus rapide et le meilleur
Le problème ici est que cette approche n'est pas évolutive et sera lente si update_audit
est un grand ensemble de données. Le MVP Richard Low a un excellent article sur les index secondaires ( The Sweet Spot For Cassandra Secondary Indexing ), et en particulier sur ce point:
Si votre table était nettement plus grande que la mémoire, une requête serait très lente, même pour renvoyer seulement quelques milliers de résultats. Renvoyer potentiellement des millions d'utilisateurs serait désastreux même si cela semble être une requête efficace.
...
En pratique, cela signifie que l'indexation est la plus utile pour renvoyer des dizaines, voire des centaines de résultats. Gardez cela à l'esprit lorsque vous envisagez d'utiliser un index secondaire.
Maintenant, votre approche de restreindre d'abord par une partition spécifique vous aidera (car votre partition devrait certainement tenir en mémoire). Mais je pense que le choix le plus performant ici serait de faire record_link_id
une clé de clustering, au lieu de s'appuyer sur un index secondaire.
Modifier
Comment le fait d'avoir un index sur un indice de cardinalité faible lorsqu'il y a des millions d'utilisateurs évolue-t-il même lorsque nous fournissons la clé primaire
Cela dépendra de la largeur de vos rangées. La chose délicate à propos des index de cardinalité extrêmement bas est que le% de lignes retournées est généralement plus élevé. Par exemple, considérons une table users
à lignes larges. Vous limitez par la clé de partition dans votre requête, mais il reste 10 000 lignes renvoyées. Si votre index est sur quelque chose comme gender
, votre requête devra filtrer environ la moitié de ces lignes, ce qui ne fonctionnera pas bien.
Les index secondaires tendent à mieux fonctionner (faute d'une meilleure description) sur la cardinalité "au milieu de la route". En utilisant l'exemple ci-dessus d'une table à lignes larges users
, un index sur country
ou state
devrait fonctionner bien mieux qu'un index sur gender
(en supposant que la plupart de ces utilisateurs ne vivent pas tous dans le même pays ou état).
Modifier 20180913
Pour votre réponse à la 1ère question "Comment la requête ci-dessus fonctionnera-t-elle en interne dans cassandra?", Savez-vous quel est le comportement lors d'une requête avec pagination?
Considérez le diagramme suivant, extrait de la documentation du pilote Java (v3.6):
Fondamentalement, la pagination provoquera la rupture de la requête et son retour au cluster pour la prochaine itération des résultats. Il serait moins probable que le délai expire, mais les performances baisseront, proportionnelles à la taille de l'ensemble de résultats total et au nombre de nœuds dans le cluster.
TL; DR; Plus les résultats demandés sont répartis sur plus de nœuds, plus cela prendra de temps.
La requête avec uniquement un index secondaire est également possible dans Cassandra 2.x
sélectionnez * dans update_audit où record_link_id = 9897;
Mais cela a un impact important sur la récupération des données, car il lit toutes les partitions sur un environnement distribué. Les données extraites par cette requête ne sont pas non plus cohérentes et n'ont pas pu les relayer.
Suggestion:
L'utilisation de l'index secondaire est considérée comme une requête DIRT de la vue NoSQL Data Model.
Pour éviter un index secondaire, nous pourrions créer une nouvelle table et y copier des données. Comme il s'agit d'une requête de l'application, les tables sont dérivées de requêtes.