Condividi tramite


Guida basata su scenari per l'indicizzazione in Azure DocumentDB

Gli indici sono strutture che migliorano la velocità di recupero dei dati abilitando l'accesso rapido a campi specifici all'interno di una raccolta. Questo articolo illustra come eseguire l'indicizzazione a vari livelli di annidamento ed esamina come esaminare in modo efficace l'utilizzo di questi indici.

Scenari di indicizzazione

Si lavorerebbe su scenari di esempio con contesto per il codice JSON di esempio definito.

{
  "_id": "e79b564e-48b1-4f75-990f-e62de2449239",
  "car_id":"AZ-9874532",
  "car_info": {
    "make": "Mustang",
    "model": "GT Fastback",
    "year": 2024,
    "registration": {
      "license_plate": "LJX386",
      "state": "WV",
      "registration_datetime": {
        "$date": "2024-01-10T01:16:44.000Z"
      },
      "expiration_datetime": {
        "$date": "2034-01-10T01:16:44.000Z"
      }
    }
  },
  "rental_history": [
    {
      "rental_id": "RT63857499825952",
      "customer_id": "CX8716",
      "start_date": {
        "$date": "2024-02-29T01:16:44.000Z"
      },
      "end_date": {
        "$date": "2024-03-04T16:54:44.000Z"
      },
      "pickup_location": { "type": "Point", "coordinates": [ -73.97, 40.77 ]
      },
      "drop_location": { "type": "Point", "coordinates": [ -73.96, 40.78 ]
      },
      "total_price": 232.56944444444443,
      "daily_rent": 50,
      "complains": [ 
        {
          "complain_id": "CMP638574998259520",
          "issue": "Strange odor inside the car.",
          "reported_datetime": {
            "$date": "2024-03-03T20:11:44.000Z"
          },
          "reported_medium": "Website",
          "resolutions": [
            {
              "resolution_datetime": {
                "$date": "2024-03-03T20:20:44.000Z"
              },
              "solution": "Inspect for any leftover food, spills, or trash that might be causing the odor. Contact the rental agency.",
              "resolved": true
            }
          ]
        }
      ],
      "accidents": [
        {
          "accident_id": "ACC376184",
          "date": {
            "$date": "2024-03-03T01:47:44.000Z"
          },
          "description": "Collisions with Soft Barriers: Accidents involving hitting bushes, shrubs, or other soft barriers.",
          "repair_cost": 147
        }
      ]
    },
    {
      "rental_id": "RT63857499825954",
      "customer_id": "CX1412",
      "start_date": {
        "$date": "2033-11-18T01:16:44.000Z"
      },
      "end_date": {
        "$date": "2033-11-25T21:11:44.000Z"
      },
      "pickup_location": { "type": "Point", "coordinates": [ 40, 5 ]
      },
      "drop_location": { "type": "Point", "coordinates": [ 41, 11 ]
      },
      "total_price": 305.3645833333333,
      "daily_rent": 39,
      "complains": [
        {
          "complain_id": "CMP638574998259540",
          "issue": "Unresponsive infotainment system.",
          "reported_datetime": {
            "$date": "2033-11-19T17:55:44.000Z"
          },
          "reported_medium": "Agency",
          "resolutions": []
        }
      ],
      "accidents": null
    }
  ],
  "junk": null
}

Indicizzazione del campo radice

Azure DocumentDB supporta gli indici nelle proprietà radici. L'esempio consente la ricerca sampleColl per car_id.

CarData> db.sampleColl.createIndex({"car_id":1})

Il piano di esecuzione consente di esaminare l'utilizzo dell'indice creato nel car_id campo con explain.

CarData> db.sampleColl.find({"car_id":"ZA-XWB804"}).explain()

{
  explainVersion: 2,
  command: "db.runCommand({explain: { 'find' : 'sampleColl', 'filter' : { 'car_id' : 'ZA-XWB804' } }})",
  explainCommandPlanningTimeMillis: 0.156,
  explainCommandExecTimeMillis: 37.956,
  dataSize: '32 kB',
  queryPlanner: {
    namespace: 'CarData.sampleColl',
    winningPlan: {
      stage: 'FETCH',
      estimatedTotalKeysExamined: 8700,
      inputStage: {
        stage: 'IXSCAN',
        indexName: 'car_id_1',
        isBitmap: true,
        indexFilterSet: [ { '$eq': { car_id: 'ZA-XWB804' } } ],
        estimatedTotalKeysExamined: 174
      }
    }
  },
  ok: 1
}

Indicizzazione delle proprietà annidate

Azure DocumentDB consente l'indicizzazione delle proprietà dei documenti incorporate. Nell'esempio viene creato un indice sul campo registration_datetime all'interno di un documento registrationannidato.

CarData> db.sampleColl.createIndex({"car_info.registration.registration_datetime":1})

L’esame del piano di esecuzione con explain fornisce informazioni dettagliate sull'analisi dell'indice.

CarData> db.sampleColl.find({"car_info.registration.registration_datetime":
                              {  $gte : new ISODate("2024-05-01")
                                ,$lt: ISODate("2024-05-07")
                              }
                            }).explain()


{
  explainVersion: 2,
  command: "db.runCommand({explain: { 'find' : 'sampleColl', 'filter' : { 'car_info.registration.registration_datetime' : { '$gte' : ISODate('2024-05-01T00:00:00Z'), '$lt' : ISODate('2024-05-07T00:00:00Z') } } }})",
  explainCommandPlanningTimeMillis: 0.095,
  explainCommandExecTimeMillis: 42.703,
  dataSize: '4087 kB',
  queryPlanner: {
    namespace: 'CarData.sampleColl',
    winningPlan: {
      stage: 'FETCH',
      estimatedTotalKeysExamined: 4350,
      inputStage: {
        stage: 'IXSCAN',
        indexName: 'car_info.registration.registration_datetime_1',
        isBitmap: true,
        indexFilterSet: [
          {
            '$range': {
              'car_info.registration.registration_datetime': {
                min: ISODate("2024-05-01T00:00:00.000Z"),
                max: ISODate("2024-05-07T00:00:00.000Z"),
                minInclusive: true,
                maxInclusive: false
              }
            }
          }
        ],
        estimatedTotalKeysExamined: 2
      }
    }
  },
  ok: 1
}

Indicizzazione delle matrici nella radice

Azure DocumentDB consente l'indicizzazione della proprietà radice definita come matrice. Si consideri l'esempio JSON seguente.

{
  "_id": ObjectId("58f56170ee9d4bd5e610d644"),
  "id": 1,
  "num": 001,
  "name": "Bulbasaur",
  "img": "http://www.serebii.net/pokemongo/pokemon/001.png",
  "type": [ 'Grass', 'Poison' ],
  "height": '0.71 m',
  "weight": '6.9 kg',
  "avg_spawns": 69,
  "spawn_time": "20:00",
  "multipliers": [ 1.58 ],
  "weaknesses": [ "Fire", "Ice", "Flying", "Psychic"],
  "next_evolution": [ { "num": "002", "name": "Ivysaur" }, { "num": "003", "name": "Venusaur" }]
}

In questo esempio viene creato un indice sul weaknesses campo della matrice e viene esaminata l'esistenza di tutti e tre i valori Ground, Water e Fire nella matrice.

Cosmicworks> db.Pokemon.createIndex({'weaknesses':1})

Cosmicworks> db.Pokemon.find({"weaknesses":
                                {$all:["Ground","Water","Fire"]}
                              }
                            ).explain()

{
  explainVersion: 2,
  command: "db.runCommand({explain: { 'find' : 'Pokemon', 'filter' : { 'weaknesses' : { '$all' : ['Ground', 'Water', 'Fire'] } } }})",
  explainCommandPlanningTimeMillis: 10.161,
  explainCommandExecTimeMillis: 21.64,
  dataSize: '906 bytes',
  queryPlanner: {
    namespace: 'Cosmicworks.Pokemon',
    winningPlan: {
      stage: 'FETCH',
      estimatedTotalKeysExamined: 50,
      inputStage: {
        stage: 'IXSCAN',
        indexName: 'weaknesses_1',
        isBitmap: true,
        indexFilterSet: [
          { '$all': { weaknesses: [ 'Ground', 'Water', 'Fire' ] } }
        ],
        estimatedTotalKeysExamined: 2
      }
    }
  },
  ok: 1
}

Annotazioni

Per MongoServerError: la chiave di indice è troppo grande.

Creare una richiesta di supporto per abilitare l'indicizzazione in background, seguita da enableLargeIndexKeys

db.runCommand({ createIndexes: "collectionName", indexes: [{ {"index_spec"}], enableLargeIndexKeys: true });

Indicizzazione di matrici annidate

Azure DocumentDB consente l'indicizzazione di matrici annidate. Nell'esempio viene creato un indice sul resolutions campo esistente all'interno della complains matrice.

CarData> db.sampleColl.createIndex({"rental_history.complains.resolutions":1})

Il piano viene esaminato con explain per identificare tutti i noleggi senza risoluzione fornita al cliente.

CarData> db.sampleColl.find({"rental_history.complains.resolutions":{ $exists: false, $ne: []}}).explain()

{
  explainVersion: 2,
  command: "db.runCommand({explain: { 'find' : 'sampleColl', 'filter' : { 'rental_history.complains.resolutions' : { '$exists' : false, '$ne' : [] } } }})",
  explainCommandPlanningTimeMillis: 0.12,
  explainCommandExecTimeMillis: 48.721000000000004,
  dataSize: '1747 kB',
  queryPlanner: {
    namespace: 'CarData.sampleColl',
    winningPlan: {
      stage: 'FETCH',
      estimatedTotalKeysExamined: 1933,
      inputStage: {
        stage: 'IXSCAN',
        indexName: 'rental_history.complains.resolutions_1',
        isBitmap: true,
        indexFilterSet: [
          {
            '$exists': { 'rental_history.complains.resolutions': false }
          },
          { '$ne': { 'rental_history.complains.resolutions': [] } }
        ],
        estimatedTotalKeysExamined: 2
      }
    }
  },
  ok: 1
}

Indicizzazione di un campo specifico in una matrice

Azure DocumentDB consente l'indicizzazione dei campi all'interno di una matrice. Nell'esempio viene creato un indice sul date campo all'interno della accidents matrice.

CarData> db.sampleColl.createIndex({"rental_history.accidents.date":1})

La query di esempio valuta gli incidenti tra un intervallo di tempo e mostra l'indice creato sulla date proprietà utilizzata.

CarData> db.sampleColl.find({"rental_history.accidents.date":
                                { $gte : ISODate("2024-05-01")
                                , $lt  : ISODate("2024-05-07")
                                }
                            }).explain()

{
  explainVersion: 2,
  command: "db.runCommand({explain: { 'find' : 'sampleColl', 'filter' : { 'rental_history.accidents.date' : { '$gte' : ISODate('2024-05-01T00:00:00Z'), '$lt' : ISODate('2024-05-07T00:00:00Z') } } }})",
  explainCommandPlanningTimeMillis: 19.816,
  explainCommandExecTimeMillis: 48.359,
  dataSize: '12 MB',
  queryPlanner: {
    namespace: 'CarData.sampleColl',
    winningPlan: {
      stage: 'FETCH',
      estimatedTotalKeysExamined: 4350,
      inputStage: {
        stage: 'IXSCAN',
        indexName: 'rental_history.accidents.date_1',
        isBitmap: true,
        indexFilterSet: [
          {
            '$range': {
              'rental_history.accidents.date': {
                min: ISODate("2024-05-01T00:00:00.000Z"),
                max: ISODate("2024-05-07T00:00:00.000Z"),
                minInclusive: true,
                maxInclusive: false
              }
            }
          }
        ],
        estimatedTotalKeysExamined: 2
      }
    }
  },
  ok: 1
}

Annotazioni

Attualmente è in corso il miglioramento del supporto per le matrici annidate. In alcuni casi perimetrali, operazioni di indicizzazione specifiche possono causare errori.

Indicizzazione con caratteri jolly escludendo i campi annidati

Azure DocumentDB supporta indici wildcard. L'esempio consente di escludere l'indicizzazione di tutti i campi annidati all'interno del documento car_info.

// Excludes all the nested sub-document property 
CarData> db.sampleColl.createIndex(  {"$**":1}
                                    ,{"wildcardProjection":
                                          {  "car_info.make":0
                                            ,"car_info.model":0
                                            ,"car_info.registration":0
                                            ,"car_info.year":0
                                            ,"rental_history":0
                                          }
                                      }
                                  )

Il piano di esecuzione non mostra alcun supporto per le query eseguite sul campo model, escluso durante la creazione dell'indice wildcard.

CarData> db.sampleColl.find({"car_info.model":"GT Fastback"}).explain()
{
  explainVersion: 2,
  command: "db.runCommand({explain: { 'find' : 'sampleColl', 'filter' : { 'car_info.model' : 'GT Fastback' } }})",
  explainCommandPlanningTimeMillis: 10.879,
  explainCommandExecTimeMillis: 374.25100000000003,
  dataSize: '0 bytes',
  queryPlanner: {
    namespace: 'CarData.sampleColl',
    winningPlan: {
      stage: 'COLLSCAN',
      runtimeFilterSet: [ { '$eq': { 'car_info.model': 'GT Fastback' } } ],
      estimatedTotalKeysExamined: 8700
    }
  },
  ok: 1
}

Indicizzazione con caratteri jolly escludendo gli oggetti annidati

Azure DocumentDB supporta gli indici con caratteri jolly. L'esempio consente di escludere oggetti annidati dal documento.

// Wildcard index excluding nested object
[mongos] CarData> db.sampleColl.createIndex( {"$**":1},
                                             {"wildcardProjection":
                                                    {  "car_info":0
                                                      ,"rental_history":0
                                                    }
                                              }
                                            )

Il piano di esecuzione non mostra alcun supporto per le query eseguite nel campo make annidato all'interno del car_info documento.

CarData> db.sampleColl.find({"car_info.make":"Mustang"}).explain()
{
  explainVersion: 2,
  command: "db.runCommand({explain: { 'find' : 'sampleColl', 'filter' : { 'car_info.make' : 'Mustang' } }})",
  explainCommandPlanningTimeMillis: 21.271,
  explainCommandExecTimeMillis: 337.475,
  dataSize: '0 bytes',
  queryPlanner: {
    namespace: 'CarData.sampleColl',
    winningPlan: {
      stage: 'COLLSCAN',
      runtimeFilterSet: [ { '$eq': { 'car_info.make': 'Mustang' } } ],
      estimatedTotalKeysExamined: 8700
    }
  },
  ok: 1
}

Indicizzazione con caratteri jolly escludendo i campi con matrice annidata

Nell'esempio di indice con caratteri jolly si consente di escludere i campi dalla matrice annidata. Viene usata la raccolta pokemon con il formato JSON evidenziato.

{
{
  "_id": ObjectId("58f56170ee9d4bd5e610d644"),
  "id": 1,
  "num": 001,
  "name": "Bulbasaur",
  "img": "http://www.serebii.net/pokemongo/pokemon/001.png",
  "type": [ 'Grass', 'Poison' ],
  "height": '0.71 m',
  "weight": '6.9 kg',
  "avg_spawns": 69,
  "spawn_time": "20:00",
  "multipliers": [ 1.58 ],
  "weaknesses": [ "Fire", "Ice", "Flying", "Psychic"],
  "next_evolution": [ { "num": "002", "name": "Ivysaur" }, { "num": "003", "name": "Venusaur" }]
}
}

Viene creato un indice su tutti i campi all'interno del file JSON, escludendo i campi num e name da un array.

Cosmicworks> db.Pokemon.createIndex( {"$**":1},
                                     {"wildcardProjection":
                                        {  "id":0
                                          ,"name":0
                                          ,"multipliers":0
                                          ,"next_evolution.num":0
                                          ,"next_evolution.name":0
                                        }
                                      }
                                    )

Il piano esplicativo non prevede alcun utilizzo dell'indice durante l'esecuzione di query sul campo name all'interno della matrice next_evolution.

Cosmicworks> db.Pokemon.find({"next_evolution.name":"Venusaur"}).explain()
{
  explainVersion: 2,
  command: "db.runCommand({explain: { 'find' : 'Pokemon', 'filter' : { 'next_evolution.name' : 'Venusaur' } }})",
  explainCommandPlanningTimeMillis: 0.799,
  explainCommandExecTimeMillis: 0.869,
  dataSize: '1090 bytes',
  queryPlanner: {
    namespace: 'Cosmicworks.Pokemon',
    winningPlan: {
      stage: 'COLLSCAN',
      runtimeFilterSet: [ { '$eq': { 'next_evolution.name': 'Venusaur' } } ],
      estimatedTotalKeysExamined: 76
    }
  },
  ok: 1
}

Passaggi successivi