Gerenciar indexação no Azure Cosmos DB para MongoDB

APLICA-SE A: MongoDB

O Azure Cosmos DB para 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 para MongoDB. Os índices são estruturas de dados especializadas que tornam a consulta dos seus dados aproximadamente uma ordem de grandeza mais rápida.

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

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

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

Editando a política de indexação

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

Indexing policy editor

Nota

Não é possível criar índices compostos usando o editor de políticas de indexação no Data Explorer.

Tipos de índice

Campo único

Você pode criar índices em qualquer campo. A ordem de classificação do índice de campo único não importa. O comando a seguir 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, índices compostos são necessários se sua consulta precisar da capacidade de classificar em vários campos de uma só vez. Para consultas com vários filtros que não precisam classificar, crie vários índices de campo único em vez de um índice composto para economizar nos custos de indexação.

Um índice composto ou índices de campo único para cada campo no índice composto resulta no mesmo desempenho para 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á como pretendido. Se o campo aninhado contiver uma matriz (em qualquer lugar do caminho), esse valor será ignorado no índice.

Como exemplo, um índice composto contendo people.dylan.age funciona neste caso, uma vez que não há nenhuma 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 ativado para sua conta de banco de dados ativando o recurso 'EnableUniqueCompoundNestedDocs'.

Nota

Não é possível 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 eficientemente em vários campos de uma só vez, 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 eficientemente uma consulta com a ordem de classificação oposta em todos os campos. Eis um exemplo:

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

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

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

Índices multichave

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

Índices geoespaciais

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

Aqui está um exemplo de criação de um índice geoespacial no location campo:

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

Índices de texto

Atualmente, o Azure Cosmos DB para MongoDB não oferece suporte a índices de texto. Para consultas de pesquisa de texto em cadeias de caracteres, você deve usar a integração do Azure AI Search 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 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 quiser indexar todos os dados na children matriz, você tem duas opções: criar índices separados para cada propriedade individual ou criar um índice curinga para toda children a matriz.

Criar um índice curinga

O comando a seguir cria um índice curinga em todas as propriedades dentro do children:

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

Ao contrário do MongoDB, os índices curinga podem suportar 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

Indexação de 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

Nota

Se você está apenas começando 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 de consultas.

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

Nota

O suporte para índice exclusivo em coleções existentes com dados está disponível na visualização. Esse recurso pode ser habilitado para sua conta de banco de dados ativando o recurso 'EnableUniqueIndexReIndex'.

Limitações

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

  • Compostos
  • TTL
  • Exclusivo

Ao contrário do MongoDB, no Azure Cosmos DB para MongoDB você não pode usar índices curinga para:

  • Criar um índice de carateres universais que inclui vários campos específicos

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

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

Como alternativa, pode criar vários índices de carateres universais.

Propriedades do índice

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

Índices exclusivos

Os índices exclusivos são úteis para impor que dois ou mais documentos não contenham o mesmo valor para campos indexados.

O comando a seguir 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 shard (partição) para criar um índice exclusivo. Em outras palavras, todos os índices exclusivos em uma coleção fragmentada são índices compostos onde um dos campos é a chave de estilhaço. O primeiro campo na ordem deve ser a chave de estilhaço.

Os comandos a seguir criam uma coleção coll fragmentada (a chave de 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, omitir a cláusula retorna um erro com a "university":1 seguinte mensagem:

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.

Índices exclusivos 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á como pretendido. Se o campo aninhado contiver uma matriz (em qualquer lugar do caminho), esse valor será ignorado no índice exclusivo e a exclusividade não será preservada para esse valor.

Por exemplo, um índice exclusivo em people.tom.age funcionará neste caso, uma vez que não há nenhuma 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 ativado para sua conta de banco de dados ativando o recurso 'EnableUniqueCompoundNestedDocs'.

Índices TTL

Para habilitar a expiração de documentos em uma coleção específica, você precisa criar um índice TTL (time-to-live). Um índice TTL é um índice no _ts campo com um expireAfterSeconds valor.

Exemplo:

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

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

Nota

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

Acompanhe o progresso do índice

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

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

  • Obtenha o progresso do índice de 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 resultados de progresso do índice

Os detalhes de 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 um banco de dados "foo" collection e "bar" que esteja 60% concluída terá o seguinte documento de saída. O Inprog[0].progress.total campo mostra 100 como a porcentagem de conclusão da meta.

    {
          "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 tiver acabado de ser iniciada em um banco de dados "foo" collection e "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 termina, o documento de saída mostra operações vazias inprog .

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

Atualizações de índice em segundo plano

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

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

Ao remover índices e executar imediatamente consultas com filtros nos índices descartados, os resultados podem 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 recém-removidos. A maioria dos desenvolvedores não descarta índices e, em seguida, imediatamente tenta consultá-los, portanto, na prática, essa situação é improvável.

Comando ReIndex

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

Você pode executar o reIndex comando usando a seguinte sintaxe:

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

Você pode usar a sintaxe abaixo para verificar se a execução do comando melhoraria o desempenho da reIndex 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 reIndex melhorar o desempenho da consulta, requiresReIndex será true. Se reIndex não melhorar o desempenho da consulta, essa propriedade será omitida.

Migrar coleções com índices

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

Indexação para MongoDB versão 3.2

Os recursos e padrões de indexação disponíveis são diferentes para contas do Azure Cosmos DB que são compatíveis com a versão 3.2 do protocolo de conexão MongoDB. 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 para MongoDB, a versão 3.2 indexa todas as propriedades por padrão. Você pode usar o seguinte comando para descartar esses índices padrão para 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 contêm 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óximos passos