Todos os produtos
Search
Central de documentação

ApsaraDB for MongoDB:Planos de consulta e replanejamento de consultas

Última atualização: Jun 26, 2026

Entenda como funcionam os planos de consulta do MongoDB, por que o replanejamento ocorre e como resolver problemas relacionados.

Query planner

O query planner do MongoDB seleciona e armazena em cache o plano de consulta mais eficiente para cada consulta com base nos índices disponíveis.

image

O query planner avalia os planos candidatos pelo número de unidades de trabalho (works) que cada um exige e, em seguida, armazena o plano vencedor em cache. As entradas em cache são reutilizadas para consultas com o mesmo query shape.

As entradas do plan cache têm três estados:

  • Missing: Nenhum plano existe no cache.

  • Inactive: O plano existe no cache com um valor works avaliado e pode ser promovido para ativo.

  • Active: O plano vencedor no cache. Pode ser rebaixado para inativo.

O plan cache é armazenado em memória e não persiste em disco. O cache é apagado quando a instância do MongoDB é reiniciada ou quando uma coleção ou índice é removido. O cache tem um limite de tamanho e usa evicção LRU.

Use os seguintes comandos para gerenciar planos de consulta:

  • Limpe o plan cache de uma coleção.

    db.<collection>.getPlanCache().clear()
  • Liste todos os query shapes de uma coleção.

    db.<collection>.getPlanCache().listQueryShapes()
  • Visualize os planos em cache para um query shape.

    db.<collection>.getPlanCache().getPlansByQuery({"query": {"name": "testname"}, "sort": { "name": 1 })

QueryHash e planCacheKey

A partir do MongoDB 4,2, cada query shape recebe um queryHash exclusivo. O planCacheKey depende tanto do query shape quanto dos índices disponíveis. Adicionar ou remover um índice compatível com o query shape altera o planCacheKey, mas não o queryHash.

Exemplo de coleção com os seguintes índices e query shapes:

  • Índices

    db.foo.createIndex( { x: 1 } )
    db.foo.createIndex( { x: 1, y: 1 } )
    db.foo.createIndex( { x: 1, z: 1 }, { partialFilterExpression: { x: { $gt: 10 } } } )
  • Query shapes

    db.foo.explain().find( { x: { $gt: 5 } } )  // Query operation 1
    db.foo.explain().find( { x: { $gt: 20 } } ) // Query operation 2

O terceiro índice é compatível com a consulta 2, mas não com a consulta 1; portanto, as duas consultas têm plan cache keys diferentes. Adicionar o índice {x:1, a:1} atualiza ambas as cache keys.

Replanejamento de consultas

À medida que os dados da coleção mudam, um plano de consulta em cache pode se tornar subótimo e precisar ser adaptado.

Quando uma consulta corresponde a um plano em cache, o planner o reutiliza diretamente enquanto monitora o desempenho. Se o plano em cache se tornar significativamente menos eficiente — por exemplo, mais de 10 vezes mais lento — do que uma alternativa, o planner interrompe a execução, remove o plano do cache e reavalia todos os candidatos. Esse processo é chamado de replanejamento de consultas.

Impactos e soluções

A palavra-chave "replanned":true no log de consultas lentas indica que o planner não consegue encontrar um plano consistentemente eficaz para um determinado query shape.

Exemplo de entrada no log de consultas lentas:

"replanned":true,"replanReason":"cached plan was less efficient than expected: expected trial execution to take X works but it took at least 10X works"

Impactos

  • Degrada o desempenho das consultas.

  • Causa contenção de mutex lock e alta utilização de CPU.

Soluções

  • Temporariamente, atualize a especificação da instância para reduzir a carga no banco de dados.

  • Limpe o plan cache e verifique se o planner seleciona um plano melhor.

  • Use hint() na sua aplicação para especificar um índice para condições de consulta que causam replanejamento:

    db.<collection>.find({a:"ABC"},{b:1,_id:0}).sort({c:1}).hint({ a: 1, c: 1, b: 1} )
    Nota

    Um hint substitui o comportamento padrão do query planner.

  • Use um index filter para restringir os índices em consultas que disparam replanejamento:

    // Check if the index exists
    db.<collection>.getIndexes()
    
    // Set the index filter
    db.runCommand(
       {
          planCacheSetFilter: "<collection>",
          query: { a: "ABC" },
          projection: { b: 1, _id: 0 },
          sort: { c: 1 },
          indexes: [
             { a: 1, c: 1 , b: 1 }
          ]
       }
    )
    // Remove the previous filter
    db.runCommand(
       {
          planCacheClearFilters: "<collection>"
       }
    )
    Nota
    • Index filters substituem o comportamento padrão do query planner.

    • Se uma consulta tiver tanto um hint quanto um index filter, o index filter tem precedência. Use index filters com cautela. Index Filters.

    • O otimizador de consultas usa um collection scan (COLLSCAN) ou o índice especificado em planCacheSetFilter. Se o índice especificado não existir ou estiver oculto, o otimizador recorre a um collection scan, o que pode causar alto uso de CPU e picos de I/O. Antes de executar planCacheSetFilter, use db.<collection>.getIndexes() para verificar se o índice existe. planCacheSetFilter.

  • (Recomendado) Otimize suas consultas e índices para evitar o replanejamento.

    Nota

    Hints e index filters são recursos paliativos. Revisar suas consultas, índices e o schema dos documentos geralmente produz resultados mais eficazes.

  • (Recomendado) Para instâncias com versão principal 4,2 ou 4,4, atualize para a versão secundária de kernel mais recente a fim de reduzir a contenção de mutex lock (SERVER-40805), ou faça upgrade para a versão principal 5,0 ou 6,0. Atualize a versão secundária do banco de dados. Atualize a versão principal do banco de dados.

Se nenhuma dessas soluções resolver o problema, envie um ticket para obter suporte técnico.

Documentação relacionada