Compreenda o desempenho das consultas através da funcionalidade Query Explain

A funcionalidade Query Explain permite-lhe enviar consultas do Firestore no modo nativo para o back-end e receber estatísticas de desempenho detalhadas sobre a execução de consultas no back-end em troca. Funciona como a operação EXPLAIN [ANALYZE] em muitos sistemas de bases de dados relacionais.

Os pedidos de explicação de consultas podem ser enviados através das bibliotecas cliente do servidor do Firestore.

Os resultados da explicação das consultas ajudam a compreender como as consultas são executadas, mostrando ineficiências e a localização de prováveis gargalos do lado do servidor.

Explicar consulta:

  • Fornece estatísticas sobre a fase de planeamento de consultas para que possa ajustar os seus índices de consultas e aumentar a eficiência.
  • A opção de análise ajuda a compreender o custo e o desempenho com base em cada consulta e permite iterar rapidamente diferentes padrões de consulta para otimizar a respetiva utilização.

Compreenda as opções de explicação de consultas: predefinição e análise

As operações de explicação de consultas podem ser realizadas através da opção predefinição ou da opção analisar.

Com a opção predefinida, o Query Explain planeia a consulta, mas ignora a fase de execução. Esta ação devolve informações da fase de planeamento. Pode usar esta opção para verificar se uma consulta tem os índices necessários e compreender que índices são usados. Isto ajuda a verificar, por exemplo, se uma determinada consulta está a usar um índice composto em vez de ter de fazer a interseção em muitos índices diferentes.

Com a opção de análise, o Query Explain planeia e executa a consulta. Isto devolve todas as informações do planeador mencionadas anteriormente, juntamente com as estatísticas do tempo de execução da consulta. Isto inclui as informações de faturação da consulta, juntamente com estatísticas ao nível do sistema sobre a execução da consulta. Pode usar estas ferramentas para testar várias configurações de consultas e índices para otimizar o respetivo custo e latência.

Quanto custa o comando Query Explain?

Quando usa o comando Query Explain com a opção predefinida, não são realizadas operações de leitura nem de índice. Independentemente da complexidade da consulta, é cobrada uma operação de leitura.

Quando usa a opção de análise da funcionalidade Explicar consulta, são realizadas operações de indexação e leitura, pelo que lhe é cobrado o valor da consulta como habitualmente. Não existe qualquer custo adicional para a atividade de análise, apenas o custo habitual da consulta que está a ser executada.

Use a opção Explicar consulta com a opção predefinida

Pode usar as bibliotecas cliente para enviar um pedido de opção predefinida.

Tenha em atenção que os pedidos são autenticados com o IAM, usando as mesmas autorizações para operações de consulta normais. Outras técnicas de autenticação, como a autenticação do Firebase, são ignoradas. Para mais informações, consulte o guia sobre a IAM para bibliotecas de cliente de servidor.

Java (administrador)

Query q = db.collection("col").whereGreaterThan("a", 1);
ExplainOptions options = ExplainOptions.builder().build();

ExplainResults<QuerySnapshot> explainResults = q.explain(options).get();
ExplainMetrics metrics = explainResults.getMetrics();
PlanSummary planSummary = metrics.getPlanSummary();

    
Nó (administrador)

const q = db.collection('col').where('country', '=', 'USA');
const options = { analyze : 'false' };

const explainResults = await q.explain(options);

const metrics = explainResults.metrics;
const plan = metrics.planSummary;

    

O formato exato da resposta depende do ambiente de execução. Os resultados devolvidos podem ser convertidos em JSON. Por exemplo:

{
    "indexes_used": [
        {"query_scope": "Collection", "properties": "(category ASC, __name__ ASC)"},
        {"query_scope": "Collection", "properties": "(country ASC, __name__ ASC)"},
    ]
}

Para mais informações, consulte a referência do relatório de explicação de consultas.

Use a explicação de consultas com a opção de análise

Pode usar as bibliotecas cliente para enviar um pedido de opção de análise.

Tenha em atenção que os pedidos são autenticados com o IAM, usando as mesmas autorizações para operações de consulta normais. Outras técnicas de autenticação, como a autenticação do Firebase, são ignoradas. Para mais informações, consulte o guia sobre a IAM para bibliotecas de cliente de servidor.

Java (administrador)

Query q = db.collection("col").whereGreaterThan("a", 1);

ExplainOptions options = ExplainOptions.builder().setAnalyze(true).build();

ExplainResults<QuerySnapshot> explainResults = q.explain(options).get();

ExplainMetrics metrics = explainResults.getMetrics();
PlanSummary planSummary = metrics.getPlanSummary();
List<Map<String, Object>> indexesUsed = planSummary.getIndexesUsed();
ExecutionStats stats = metrics.getExecutionStats();

    
Nó (administrador)

const q = db.collection('col').where('country', '=', 'USA');

const options = { analyze : 'true' };

const explainResults = await q.explain(options);

const metrics = explainResults.metrics;
const plan = metrics.planSummary;
const indexesUsed = plan.indexesUsed;
const stats = metrics.executionStats;

    

O exemplo seguinte mostra o objeto stats devolvido, além de planInfo. O formato exato da resposta depende do ambiente de execução. A resposta de exemplo está no formato JSON.

{
    "resultsReturned": "5",
    "executionDuration": "0.100718s",
    "readOperations": "5",
    "debugStats": {
               "index_entries_scanned": "95000",
               "documents_scanned": "5"
               "billing_details": {
                     "documents_billable": "5",
                     "index_entries_billable": "0",
                     "small_ops": "0",
                     "min_query_cost": "0",
               }
    }

}

Para mais informações, consulte a referência do relatório de explicação de consultas.

Interprete os resultados e faça ajustes

Vejamos um cenário de exemplo em que consultamos filmes por género e país de produção.

Para ilustração, suponha o equivalente a esta consulta SQL.

SELECT *
FROM /movies
WHERE category = 'Romantic' AND country = 'USA';

Se usarmos a opção de análise, as métricas devolvidas mostram que a consulta é executada em dois índices de campo único, (category ASC, __name__ ASC) e (country ASC, __name__ ASC). Analisa 16 500 entradas de índice, mas devolve apenas 1200 documentos.

// Output query planning info
{
    "indexes_used": [
        {"query_scope": "Collection", "properties": "(category ASC, __name__ ASC)"},
        {"query_scope": "Collection", "properties": "(country ASC, __name__ ASC)"},
    ]
}

// Output query status
{
    "resultsReturned": "1200",
    "executionDuration": "0.118882s",
    "readOperations": "1200",
    "debugStats": {
               "index_entries_scanned": "16500",
               "documents_scanned": "1200"
               "billing_details": {
                     "documents_billable": "1200",
                     "index_entries_billable": "0",
                     "small_ops": "0",
                     "min_query_cost": "0",
               }
    }
}

Para otimizar o desempenho da execução da consulta, pode criar um índice composto totalmente coberto (category ASC, country ASC, __name__ ASC).

Se executar novamente a consulta com a opção de análise, pode ver que o índice criado recentemente está selecionado para esta consulta e que a consulta é executada muito mais rapidamente e de forma mais eficiente.

// Output query planning info
{
    "indexes_used": [
        {"query_scope": "Collection", "properties": "(category ASC, country ASC,  __name__ ASC)"}
    ]
}

// Output query stats
{
    "resultsReturned": "1200",
    "executionDuration": "0.026139s",
    "readOperations": "1200",
    "debugStats": {
               "index_entries_scanned": "1200",
               "documents_scanned": "1200"
               "billing_details": {
                     "documents_billable": "1200",
                     "index_entries_billable": "0",
                     "small_ops": "0",
                     "min_query_cost": "0",
               }
    }
}