Les index
Vous devez créer un index pour le keyspace pour pouvoir le requêter.Le service Index vous permet de créer deux types d'index: des index primaires et des index secondaires.
Jeu de données
Avant de poursuivre ce chapitre, nous allons ajouter des données à la collection étudiant.
DELETE FROM `ecole-bucket`.`ecole-scope`.etudiant; DROP PRIMARY INDEX ON `ecole-bucket`.`ecole-scope`.etudiant; DROP INDEX etudiant_idx ON `ecole-bucket`.`ecole-scope`.etudiant; DROP INDEX etudiant_nom_idx ON `ecole-bucket`.`ecole-scope`.etudiant; DROP INDEX etudiant_nom_idx2 ON `ecole-bucket`.`ecole-scope`.etudiant; INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant1", { "nom": "Benhocine", "prenom": "Rachid", "email": "rachid.benhocine@example.com", "region": "Île-de-France", "ville": "Paris", "classe": ["Informatique","Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant2", { "nom": "Martin", "prenom": "Léo", "email": "leo.martin@example.com", "region": "Centre-Val de Loire", "ville": "Tours", "classe": ["Informatique","Math","Physique"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant3", { "nom": "Masson", "prenom": "Gabriel", "email": "gabriel.masson@example.com", "region": "Normandie", "ville": "Rouen", "classe": ["Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant4", { "nom": "Millet", "prenom": "Arthur", "email": "arthur.millet@example.com", "region": "Île-de-France", "ville": "Paris", "classe": ["Informatique"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant5", { "nom": "Rousseau", "prenom": "Arthur", "email": "arthur.rousseau@example.com", "region": "Île-de-France", "ville": "Paris", "classe": ["Informatique","Math","Physique"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant6", { "nom": "Guyot", "prenom": "Arthur", "email": "arthur.guyot@example.com", "region": "Île-de-France", "ville": "Palaiseau", "classe": ["Informatique","Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant7", { "nom": "Boyer", "prenom": "Léo", "email": "leo.boyer@example.com", "region": "Normandie", "ville": "Rouen", "classe": ["Informatique","Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant8", { "nom": "Caron", "prenom": "Adam", "email": "adam.caron@example.com", "region": "Île-de-France", "ville": "Paris", "classe": ["Informatique","Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant9", { "nom": "Dumas", "prenom": "Samuel", "email": "samuel.dumas@example.com", "region": "Île-de-France", "ville": "Palaiseau", "classe": ["Informatique","Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant10", { "nom": "Garcia", "prenom": "Eva", "email": "eva.garcia@example.com", "region": "Île-de-France", "ville": "Paris", "classe": ["Informatique","Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant11", { "nom": "Maillard", "prenom": "Samuel", "email": "samuel.maillard@example.com", "region": "Normandie", "ville": "Le Havre", "classe": ["Informatique","Math","Physique"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant12", { "nom": "Collet", "prenom": "Gabriel", "email": "gabriel.collet@example.com", "region": "Normandie", "ville": "Caen", "classe": ["Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant13", { "nom": "Rousseau", "prenom": "Rayan", "email": "rayan.rousseau@example.com", "region": "Centre-Val de Loire", "ville": "Tours", "classe": ["Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant14", { "nom": "Bouvier", "prenom": "Gabriel", "email": "gabriel.bouvier@example.com", "region": "Bretagne", "ville": "Rennes", "classe": ["Physique","Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant15", { "nom": "Cousin", "prenom": "Victor", "email": "victor.cousin@example.com", "region": "Bretagne", "ville": "Brest", "classe": ["Physique","Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant16", { "nom": "Langlois", "prenom": "Sacha", "email": "sacha.langlois@example.com", "region": "Bretagne", "ville": "Rennes", "classe": ["Informatique","Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant17", { "nom": "Perrier", "prenom": "Lina", "email": "lina.perrier@example.com", "region": "Île-de-France", "ville": "Paris", "classe": ["Informatique","Physique"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant18", { "nom": "Marchal", "prenom": "Rose", "email": "rose.marchal@example.com", "region": "Île-de-France", "ville": "Boulogne-Billancourt", "classe": ["Informatique","Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant19", { "nom": "Boulanger", "prenom": "Rayan", "email": "Rayan.Boulanger@example.com", "region": "Bretagne", "ville": "Rennes", "classe": ["Informatique","Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant20", { "nom": "Boyer", "prenom": "Jade", "email": "jade.boyer@example.com", "region": "Bretagne", "ville": "Brest", "classe": ["Informatique","Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant21", { "nom": "Benhassen", "prenom": "Mohamed", "email": "mohamed.benhassen@example.com", "region": "Île-de-France", "ville": "Paris", "classe": ["Informatique","Physique"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant22", { "nom": "Grondin", "prenom": "Alice", "email": "alice.grondin@example.com", "region": "Normandie", "ville": "Le Havre", "classe": ["Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant23", { "nom": "Lacroix", "prenom": "Martin", "email": "martin.lacroix@example.com", "region": "Île-de-France", "ville": "Boulogne-Billancourt", "classe": ["Informatique","Math"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant24", { "nom": "Humbert", "prenom": "Victor", "email": "victor.humbert@example.com", "region": "Île-de-France", "ville": "Boulogne-Billancourt", "classe": ["Informatique"] }); INSERT INTO `ecole-bucket`.`ecole-scope`.etudiant (KEY, VALUE) VALUES ("etudiant25", { "nom": "Fabre", "prenom": "Axel", "email": "axel.fabre@example.com", "region": "Centre-Val de Loire", "ville": "Orléans", "classe": ["Informatique"] });
Créer un index primaire
L'index primaire est apparenté à l'index unique pour la clé primaire dans le modèle relationnel. Il s'applique aux clés des documents. Par exemple, voici comment on peut créer un index primaire pour la collection "ETUDIANT":
cbq> CREATE PRIMARY INDEX ON `ecole-bucket`.`ecole-scope`.etudiant; { "requestID": "f07039c6-64cc-470b-a6c4-aec81c4ca3df", "signature": null, "results": [ ], "status": "success", "metrics": { "elapsedTime": "2.582207836s", "executionTime": "2.582130668s", "resultCount": 0, "resultSize": 0, "serviceLoad": 12 } }
Créer un index secondaire
Pour créer un index secondaire sur le champ "nom" de la collection "ETUDIANT", vous pouvez utiliser l'exemple suivant :
cbq> CREATE INDEX etudiant_idx1 ON `ecole-bucket`.`ecole-scope`.etudiant(nom); { "requestID": "948dbfe3-6b41-4b00-b7ba-9dd8753f6f7a", "signature": null, "results": [ ], "status": "success", "metrics": { "elapsedTime": "3.738930585s", "executionTime": "3.738872219s", "resultCount": 0, "resultSize": 0, "serviceLoad": 12 } }
Il est également possible de créer un index secondaire sur plusieurs champs, comme le montre l'exemple suivant:
cbq> CREATE INDEX etudiant_idx2 ON `ecole-bucket`.`ecole-scope`.etudiant(nom, prenom); { "requestID": "1301708c-4fe4-48be-ab59-e6f64679f482", "signature": null, "results": [ ], "status": "success", "metrics": { "elapsedTime": "3.588030022s", "executionTime": "3.587957344s", "resultCount": 0, "resultSize": 0, "serviceLoad": 12 } }
Créer un index basé sur une fonction
Dans certains cas, il peut être avantageux de créer un index basé sur une fonction si cette même fonction est utilisée dans la clause WHERE.
cbq> CREATE INDEX etudiant_idx3 ON `ecole-bucket`.`ecole-scope`.etudiant(UPPER(nom)); { "requestID": "db76efd0-faeb-4205-b270-e1aa8cc6eea0", "signature": null, "results": [ ], "status": "success", "metrics": { "elapsedTime": "3.523991686s", "executionTime": "3.523874018s", "resultCount": 0, "resultSize": 0, "serviceLoad": 12 } }
Créer un index sur les métadonnées
Il est également possible d'indexer les métadonnées, comme le montre cet exemple:
cbq> CREATE INDEX etudiant_idx4 ON `ecole-bucket`.`ecole-scope`.etudiant(META().id); { "requestID": "837c6eba-a046-48c9-9083-f4730c3aab31", "signature": null, "results": [ ], "status": "success", "metrics": { "elapsedTime": "3.551928035s", "executionTime": "3.551792923s", "resultCount": 0, "resultSize": 0, "serviceLoad": 12 } }
Créer un index sur des données de type liste
Il est possible de créer un index sur des champs de type liste. On peut indexer soit les valeurs distinctes, soit toutes les valeurs de la liste comme dans cet exemple:
cbq> CREATE INDEX etudiant_idx5 ON `ecole-bucket`.`ecole-scope`.etudiant(ALL classe); { "requestID": "834e5b54-e7fb-4c81-a3d6-b434ad9f45b6", "signature": null, "results": [ ], "status": "success", "metrics": { "elapsedTime": "3.516182913s", "executionTime": "3.516121959s", "resultCount": 0, "resultSize": 0, "serviceLoad": 12 } }
Créer un index partiel
Un index partiel est un index sur un sous-ensemble de documents dans un keyspace. Par exemple, on peut indexer seulement les documents qui satisfont un filtre précis.
Dans cet exemple, unqiuement les étudiants de l'Île-de-France sont indexés.
cbq> CREATE INDEX etudiant_idx6 ON `ecole-bucket`.`ecole-scope`.etudiant(ville) where region = "Île-de-France"; { "requestID": "a220b995-66ec-49ed-8a0d-024692321f87", "signature": null, "results": [ ], "status": "success", "metrics": { "elapsedTime": "3.447694816s", "executionTime": "3.447638965s", "resultCount": 0, "resultSize": 0, "serviceLoad": 12 } }
Placement d'un index
Lors de la création d'un index, vous pouvez utiliser la clause WITH pour préciser sur quel noeud de cluster de base de données l'index doit être créé.
cbq> CREATE INDEX etudiant_idx7 ON `ecole-bucket`.`ecole-scope`.etudiant(region, ville) WITH {"nodes": ["172.18.56.11:8091"]}; { "requestID": "1107c474-d85b-4285-bb19-ef0fecefcfe2", "signature": null, "results": [ ], "status": "success", "metrics": { "elapsedTime": "3.532665788s", "executionTime": "3.532601558s", "resultCount": 0, "resultSize": 0, "serviceLoad": 12 } }
L'index partitionné
Il est possible de partitionner l'index secondaire et de placer chaque partition sur un noeud spécifique, comme cela a été mentionné précédemment.
cbq> CREATE INDEX etudiant_idx8 ON `ecole-bucket`.`ecole-scope`.etudiant(ville) PARTITION BY HASH(region); { "requestID": "6c35c6d9-60fa-42e9-921e-8a112888be49", "signature": null, "results": [ ], "status": "success", "metrics": { "elapsedTime": "5.209173115s", "executionTime": "5.209093892s", "resultCount": 0, "resultSize": 0, "serviceLoad": 12 } }
L'index peut être aussi répliqué.
Création d'index en différé
Il est possible de créer l'index de manière différée et de le construire ultérieurement.
cbq> CREATE INDEX etudiant_idx9 ON `ecole-bucket`.`ecole-scope`.etudiant(email) WITH {"defer_build":true}; { "requestID": "45461bb9-04c4-4ca6-bdc0-2ec4ec51bbc8", "signature": null, "results": [ ], "status": "success", "metrics": { "elapsedTime": "148.781802ms", "executionTime": "148.680719ms", "resultCount": 0, "resultSize": 0, "serviceLoad": 12 } }
Et pour le construire
cbq> BUILD INDEX ON `ecole-bucket`.`ecole-scope`.etudiant(etudiant_idx9); { "requestID": "ef31adfa-4e79-4b56-8485-43358b26d4ca", "signature": null, "results": [ ], "status": "success", "metrics": { "elapsedTime": "96.20431ms", "executionTime": "96.111426ms", "resultCount": 0, "resultSize": 0, "serviceLoad": 12 } }
Supprimer un index
Utilisez la commande DROP INDEX pour supprimer l'index.
cbq> DROP INDEX etudiant_idx9 ON `ecole-bucket`.`ecole-scope`.etudiant; { "requestID": "44599bc3-7c95-458b-8864-8394f4a5287f", "signature": null, "results": [ ], "status": "success", "metrics": { "elapsedTime": "137.092528ms", "executionTime": "137.029307ms", "resultCount": 0, "resultSize": 0, "serviceLoad": 12 } }
Utilisation de l'index
En fonction des filtres de la clause WHERE, couchbase Server tente de sélectionner un index secondaire approprié pour une requête. Si aucun index secondaire ne peut être utilisé, le service de l'index se rabat sur l'index primaire.
On peut utiliser EXPLAIN pour visualiser le plan d'exécution de la requête et vérifier l'utilisation de l'index.
cbq> EXPLAIN SELECT * FROM `ecole-bucket`.`ecole-scope`.etudiant WHERE nom = "Benhocine" and ville = "Paris";
{
"requestID": "11aadf70-9117-40f4-abc5-7d308554bdee",
"signature": "json",
"results": [
{
"plan": {
"#operator": "Sequence",
"~children": [
{
"#operator": "IntersectScan",
"scans": [
{
"#operator": "IndexScan3",
"bucket": "ecole-bucket",
"index": "etudiant_idx8",
"index_id": "6c9c1fb77a996049",
"index_partition_by": "[`region`]",
"index_projection": {
"primary_key": true
},
...
Il est possible d'influencer l'optimiseur en utilisant un HINT avec un autre index.
cbq> EXPLAIN SELECT /*+ INDEX(etudiant etudiant_idx1) */ * FROM `ecole-bucket`.`ecole-scope`.etudiant WHERE nom = "Benhocine" and ville = "Paris";
{
"requestID": "4c2bb23f-e19c-4893-a359-1dda626c1141",
"signature": "json",
"results": [
{
"plan": {
"#operator": "Sequence",
"~children": [
{
"#operator": "IntersectScan",
"scans": [
{
"#operator": "IndexScan3",
"bucket": "ecole-bucket",
"index": "etudiant_idx1",
"index_id": "f779a57a2f0b0758",
"index_projection": {
"primary_key": true
},
...