Gerenciar a indexação no Azure Cosmos DB for MongoDB

APLICA-SE AO: MongoDB

O Azure Cosmos DB for MongoDB aproveita os principais recursos de gerenciamento de índice do Azure Cosmos DB. Este artigo se concentra em como adicionar índices usando o Azure Cosmos DB for MongoDB. Os índices são estruturas de dados especializadas que tornam a consulta de dados aproximadamente uma ordem de magnitude mais rápida.

Indexação do servidor MongoDB versão 3.6 e superior

O servidor do Azure Cosmos DB for MongoDB versão 3.6+ indexa automaticamente o campo _id e a chave de fragmento (somente em coleções fragmentadas). A API impõe automaticamente a exclusividade do campo _id por chave de fragmento.

A API para MongoDB se comporta de maneira diferente do Azure Cosmos DB for NoSQL, que indexa todos os campos por padrão.

Editar a política de indexação

É recomendável editar sua política de indexação no Data Explorer no portal do Azure. Você pode adicionar índices de campo único e curinga do editor de políticas de indexação no Data Explorer:

Indexing policy editor

Observação

Você não pode criar índices compostos usando o editor de política de indexação no Data Explorer.

Tipos de índice

Campo único

Você pode criar índices em qualquer campo único. A ordem de classificação do índice de campo único não importa. O comando abaixo cria um índice no campo name:

db.coll.createIndex({name:1})

Você pode criar o mesmo índice de campo único no name portal do Azure:

Add name index in indexing policy editor

Uma consulta usa vários índices de campo único, quando disponíveis. Você pode criar até 500 índices de campo único por coleção.

Índices compostos (servidor MongoDB versão 3.6+)

Na API para MongoDB, os índices compostos serão necessários se a consulta precisar da capacidade de classificar em vários campos de uma só vez. Para consultas com vários filtros que não precisam ser classificados, crie vários índices de campo único em vez de um único índice composto para economizar nos custos de indexação.

Um índice composto ou índices de campo único para cada campo no índice composto resultam no mesmo desempenho para a filtragem em consultas.

Índices compostos em campos aninhados não são suportados por padrão devido a limitações com matrizes. Se o campo aninhado não contiver uma matriz, o índice funcionará conforme o esperado. Se seu campo aninhado contiver uma matriz (em qualquer lugar no caminho), esse valor será ignorado no índice.

Como exemplo, um índice composto contendo people.dylan.age funciona nesse caso, pois não há uma matriz no caminho:

{
  "people": {
    "dylan": {
      "name": "Dylan",
      "age": "25"
    },
    "reed": {
      "name": "Reed",
      "age": "30"
    }
  }
}

Esse mesmo índice composto não funciona neste caso, pois há uma matriz no caminho:

{
  "people": [
    {
      "name": "Dylan",
      "age": "25"
    },
    {
      "name": "Reed",
      "age": "30"
    }
  ]
}

Esse recurso pode ser habilitado para sua conta de banco de dados habilitando a capacidade 'EnableUniqueCompoundNestedDocs'.

Observação

Você não pode criar índices compostos em matrizes.

O comando a seguir cria um índice composto nos campos name e age:

db.coll.createIndex({name:1,age:1})

Você pode usar índices compostos para classificar, de forma eficiente, vários campos ao mesmo tempo, conforme mostrado no exemplo a seguir:

db.coll.find().sort({name:1,age:1})

Você também pode usar o índice composto anterior para classificar, de forma eficiente, uma consulta com a ordem de classificação oposta em todos os campos. Aqui está um exemplo:

db.coll.find().sort({name:-1,age:-1})

No entanto, a sequência dos caminhos no índice composto deve corresponder exatamente à consulta. Veja um exemplo de uma consulta que exigiria um índice composto adicional:

db.coll.find().sort({age:1,name:1})

Índices de várias chaves

O Azure Cosmos DB cria índices de várias chaves para indexar o conteúdo armazenado em matrizes. Se você indexar um campo com um valor de matriz, o Azure Cosmos DB indexa automaticamente todos os elementos na matriz.

Índices geoespaciais

Muitos operadores geoespaciais se beneficiarão dos índices geoespaciais. Atualmente, o Azure Cosmos DB for MongoDB dá suporte a índices 2dsphere. A API ainda não dá suporte a índices 2d.

Este é um exemplo de criação de um índice geoespacial no campo location:

db.coll.createIndex({ location : "2dsphere" })

Índices de texto

Atualmente, o Azure Cosmos DB for MongoDB não dá suporte a índices de texto. Para consultas de pesquisa de texto em cadeias de caracteres, você deve usar a integração da Pesquisa de IA do Azure com o Azure Cosmos DB.

Índices curinga

Você pode usar índices curinga para dar suporte a consultas em campos desconhecidos. Vamos imaginar que você tenha uma coleção que contém dados sobre as famílias.

Aqui está parte de um documento de exemplo nessa coleção:

"children": [
   {
     "firstName": "Henriette Thaulow",
     "grade": "5"
   }
]

Aqui está outro exemplo, desta vez com um conjunto ligeiramente diferente de propriedades em children:

"children": [
    {
     "familyName": "Merriam",
     "givenName": "Jesse",
     "pets": [
         { "givenName": "Goofy" },
         { "givenName": "Shadow" }
         ]
   },
   {
     "familyName": "Merriam",
     "givenName": "John",
   }
]

Nesta coleção, os documentos podem ter muitas propriedades possíveis diferentes. Se você quisesse indexar todos os dados na matriz children, você tem duas opções: criar índices separados para cada propriedade individual ou criar um índice curinga para toda a matriz children.

Criar um índice curinga

O comando a seguir cria um índice curinga em qualquer propriedade em children:

db.coll.createIndex({"children.$**" : 1})

Ao contrário do MongoDB, os índices curinga podem dar suporte a vários campos em predicados de consulta. Não haverá diferença no desempenho da consulta se você usar um único índice curinga em vez de criar um índice separado para cada propriedade.

Você pode criar os seguintes tipos de índice usando a sintaxe curinga:

  • Campo único
  • Geoespacial

Indexando todas as propriedades

Veja como você pode criar um índice curinga em todos os campos:

db.coll.createIndex( { "$**" : 1 } )

Você também pode criar índices curinga usando o Data Explorer no portal do Azure:

Add wildcard index in indexing policy editor

Observação

Se você estiver apenas iniciando o desenvolvimento, é altamente recomendável começar com um índice curinga em todos os campos. Isso pode simplificar o desenvolvimento e facilitar a otimização das consultas.

Documentos com muitos campos podem ter uma cobrança de alta RU (Unidade de Solicitação) para gravações e atualizações. Portanto, se você tiver uma carga de trabalho de gravação intensa, deverá optar por caminhos de índice individualmente em vez de usar índices curinga.

Observação

A compatibilidade com índice exclusivo em coleções existentes com dados está disponível na versão prévia. Esse recurso pode ser habilitado para sua conta de banco de dados habilitando a capacidade 'EnableUniqueIndexReIndex'.

Limitações

Os índices curinga não dão suporte a nenhum dos seguintes tipos de índice ou propriedades:

  • Composto
  • TTL
  • Exclusivo

Diferente do MongoDB, no Azure Cosmos DB for MongoDB, não é possível usar índices curinga para:

  • Criar um índice curinga que inclui vários campos específicos

    db.coll.createIndex(
        { "$**" : 1 },
        { "wildcardProjection " :
            {
               "children.givenName" : 1,
               "children.grade" : 1
            }
        }
    )
    
  • Criar um índice curinga que exclui vários campos específicos

    db.coll.createIndex(
        { "$**" : 1 },
        { "wildcardProjection" :
            {
               "children.givenName" : 0,
               "children.grade" : 0
            }
        }
    )
    

Como alternativa, você pode criar vários índices curinga.

Propriedades de índice

As operações a seguir são comuns para as contas atendendo o protocolo de transferência versão 4.0 e as contas que atendem a versões anteriores. Você pode saber mais sobre índices com suporte e propriedades indexadas.

Índices exclusivos

Índices exclusivos são úteis para impor que dois ou mais documentos não contém o mesmo valor para os campos indexados.

O comando abaixo cria um índice exclusivo no campo student_id:

globaldb:PRIMARY> db.coll.createIndex( { "student_id" : 1 }, {unique:true} )
{
    "_t" : "CreateIndexesResponse",
    "ok" : 1,
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "numIndexesAfter" : 4
}

Para coleções fragmentadas, você deve fornecer a chave de fragmentação (partição) para criar um índice exclusivo. Em outras palavras, todos os índices exclusivos em uma coleção fragmentada são índices compostos em que um dos campos é a chave de fragmento. O primeiro campo no pedido deve ser a chave de fragmento.

Os seguintes comandos criam uma coleção fragmentada coll (a chave do fragmento é university) com um índice exclusivo nos campos student_id e university:

globaldb:PRIMARY> db.runCommand({shardCollection: db.coll._fullName, key: { university: "hashed"}});
{
    "_t" : "ShardCollectionResponse",
    "ok" : 1,
    "collectionsharded" : "test.coll"
}
globaldb:PRIMARY> db.coll.createIndex( { "university" : 1, "student_id" : 1 }, {unique:true});
{
    "_t" : "CreateIndexesResponse",
    "ok" : 1,
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 3,
    "numIndexesAfter" : 4
}

No exemplo anterior, a omissão da cláusula "university":1 retorna a seguinte mensagem de erro:

cannot create unique index over {student_id : 1.0} with shard key pattern { university : 1.0 }

Limitações

Índices exclusivos precisam ser criados enquanto a coleção está vazia.

Por padrão, não há suporte para índices exclusivos em campos aninhados devido a limitações nas matrizes. Se o campo aninhado não contiver uma matriz, o índice funcionará conforme o esperado. Se o campo aninhado contiver uma matriz (em qualquer lugar no caminho), esse valor será ignorado no índice exclusivo e a exclusividade não será preservada nele.

Por exemplo, um índice exclusivo em people.tom.age funcionará neste caso, pois não há matriz no caminho:

{ "people": { "tom": { "age": "25" }, "mark": { "age": "30" } } }

mas não funcionará neste caso, pois há uma matriz no caminho:

{ "people": { "tom": [ { "age": "25" } ], "mark": [ { "age": "30" } ] } }

Esse recurso pode ser habilitado para sua conta de banco de dados habilitando a capacidade 'EnableUniqueCompoundNestedDocs'.

Índices TTL

Para habilitar a expiração do documento em uma determinada coleção, você precisa criar um índice de TTL (vida útil). Um índice TTL é um índice no campo _ts com um valor expireAfterSeconds.

Exemplo:

globaldb:PRIMARY> db.coll.createIndex({"_ts":1}, {expireAfterSeconds: 10})

O comando anterior exclui todos os documentos na coleção db.coll que não foram modificados nos últimos 10 segundos.

Observação

O campo _ts é específico para Azure Cosmos DB e não pode ser acessado de clientes do MongoDB. É uma propriedade reservada (sistema) que contém o carimbo de data/hora da última modificação do documento.

Acompanhar o progresso do índice

A versão 3.6+ do Azure Cosmos DB for MongoDB dá suporte ao comando currentOp() para acompanhar o progresso do índice em uma instância do banco de dados. Esse comando retorna um documento que contém informações sobre operações em andamento em uma instância do banco de dados. Você usa o comando currentOp para controlar todas as operações em andamento no MongoDB nativo. No Azure Cosmos DB for MongoDB, esse comando só dá suporte ao acompanhamento da operação de índice.

Estes são alguns exemplos que mostram como usar o comando currentOp para acompanhar o progresso do índice:

  • Obtenha o progresso do índice para uma coleção:

    db.currentOp({"command.createIndexes": <collectionName>, "command.$db": <databaseName>})
    
  • Obtenha o progresso do índice para todas as coleções em um banco de dados:

    db.currentOp({"command.$db": <databaseName>})
    
  • Obtenha o progresso do índice para todos os bancos de dados e coleções em uma conta do Azure Cosmos DB:

    db.currentOp({"command.createIndexes": { $exists : true } })
    

Exemplos de saída de progresso de índice

Os detalhes do progresso do índice mostram a porcentagem de progresso para a operação de índice atual. Aqui está um exemplo que mostra o formato do documento de saída para diferentes estágios do progresso do índice:

  • Uma operação de índice em uma coleção "foo" e banco de dados "bar" 60 por cento concluído, terá o seguinte documento de saída. O campo Inprog[0].progress.total mostra 100 como a porcentagem de conclusão de destino.

    {
          "inprog" : [
          {
                  ………………...
                  "command" : {
                          "createIndexes" : foo
                          "indexes" :[ ],
                          "$db" : bar
                  },
                  "msg" : "Index Build (background) Index Build (background): 60 %",
                  "progress" : {
                          "done" : 60,
                          "total" : 100
                  },
                  …………..…..
          }
          ],
          "ok" : 1
    }
    
  • Se uma operação de índice acabou de ser iniciada em uma coleção "foo" e no banco de dados "bar", o documento de saída poderá mostrar 0% de progresso até atingir um nível mensurável.

    {
          "inprog" : [
          {
                  ………………...
                  "command" : {
                          "createIndexes" : foo
                          "indexes" :[ ],
                          "$db" : bar
                  },
                  "msg" : "Index Build (background) Index Build (background): 0 %",
                  "progress" : {
                          "done" : 0,
                          "total" : 100
                  },
                  …………..…..
          }
          ],
         "ok" : 1
    }
    
  • Quando a operação de índice em andamento for concluída, o documento de saída mostrará operações vazias inprog.

    {
        "inprog" : [],
        "ok" : 1
    }
    

Atualizações de índice em segundo plano

Independentemente do valor especificado para a propriedade de índice em Segundo Plano, as atualizações de índice sempre são feitas em segundo plano. Como as atualizações de índice consomem as RUs (Unidades de Solicitação) em uma prioridade mais baixa que outras operações do banco de dados, as alterações do índice não resultarão em nenhum tempo de inatividade para gravações, atualizações ou exclusões.

Não há nenhum impacto na disponibilidade de leitura ao adicionar um novo índice. As consultas só utilizarão novos índices depois que a transformação do índice for concluída. Durante a transformação do índice, o mecanismo de consulta continuará a usar índices existentes, portanto, você observará um desempenho de leitura durante a transformação de indexação semelhante a aquele observado antes de iniciar a alteração de indexação. Ao adicionar novos índices, também não há nenhum risco de resultados de consulta incompletos ou inconsistentes.

Ao remover índices e executar imediatamente consultas que tenham filtros nos índices descartados, os resultados poderão ser inconsistentes e incompletos até que a transformação do índice seja concluída. Se você remover índices, o mecanismo de consulta não fornecerá resultados consistentes ou completos quando as consultas filtrarem esses índices recentemente removidos. A maioria dos desenvolvedores não remove índices e tenta imediatamente consultá-los, portanto, na prática, essa situação é improvável.

Observação

Você pode acompanhar o progresso do índice.

Reindexar o comando

O comando reIndex recriará todos os índices em uma coleção. Em alguns casos raros, o desempenho da consulta ou outros problemas de índice na sua coleção podem ser resolvidos executando o comando reIndex. Se você estiver tendo problemas com a indexação, recriar os índices com o comando reIndex é uma abordagem recomendada.

Você pode executar o comando reIndex localmente usando a sintaxe a seguir:

db.runCommand({ reIndex: <collection> })

Você pode usar a sintaxe abaixo para verificar se a execução do comandoreIndex melhorará o desempenho da consulta em sua coleção:

db.runCommand({"customAction":"GetCollection",collection:<collection>, showIndexes:true})

Saída de exemplo:

{
        "database" : "myDB",
        "collection" : "myCollection",
        "provisionedThroughput" : 400,
        "indexes" : [
                {
                        "v" : 1,
                        "key" : {
                                "_id" : 1
                        },
                        "name" : "_id_",
                        "ns" : "myDB.myCollection",
                        "requiresReIndex" : true
                },
                {
                        "v" : 1,
                        "key" : {
                                "b.$**" : 1
                        },
                        "name" : "b.$**_1",
                        "ns" : "myDB.myCollection",
                        "requiresReIndex" : true
                }
        ],
        "ok" : 1
}

Se o reIndex desempenho da consulta for aprimorado, requiresReIndex será true. Se o reIndex não melhorar o desempenho da consulta, essa propriedade será omitida.

Migrando coleções com índices

No momento, você só pode criar índices exclusivos quando a coleção não contém nenhum documento. Ferramentas de migração do MongoDB populares tentam criar índices exclusivos depois da importação dos dados. Para contornar esse problema, você pode criar manualmente as coleções correspondentes e os índices exclusivos em vez de permitir que a ferramenta de migração tente. (Você pode obter esse comportamento para mongorestore usando o sinalizador --noIndexRestore na linha de comando.)

Indexação do MongoDB versão 3.2

Os recursos de indexação disponíveis e os padrões são diferentes para contas do Azure Cosmos DB compatíveis com a versão 3.2 do protocolo de transmissão do MongoDB. Você pode verificar a versão da sua conta e atualizar para a versão 3.6.

Se você estiver usando a versão 3.2, esta seção descreve as principais diferenças com as versões 3.6+.

Descartando índices padrão (versão 3.2)

Ao contrário das versões 3.6+ do Azure Cosmos DB for MongoDB, a versão 3.2 indexa cada propriedade por padrão. Você pode usar os seguintes comandos para descartar estes índices padrão de uma coleção (coll):

> db.coll.dropIndexes()
{ "_t" : "DropIndexesResponse", "ok" : 1, "nIndexesWas" : 3 }

Depois de descartar os índices padrão, você pode adicionar mais índices como faria na versão 3.6+.

Índices compostos (versão 3.2)

Os índices compostos possuem referências a vários campos de um documento. Se você quiser criar um índice composto, atualize para a versão 3.6 ou 4.0.

Índices curinga (versão 3.2)

Se você quiser criar um índice curinga, atualize para a versão 4.0 ou 3.6.

Próximas etapas