Оптимизируйте запросы с помощью фильтров диапазона и неравенства в нескольких полях.

На этой странице представлены примеры стратегий индексирования, которые можно использовать для запросов с фильтрами по диапазону и неравенству по нескольким полям, чтобы обеспечить эффективную работу с запросами.

Прежде чем оптимизировать запросы, ознакомьтесь с соответствующими понятиями .

Оптимизируйте запросы с помощью Query Explain.

Чтобы определить, являются ли ваш запрос и индексы оптимальными, вы можете использовать функцию Query Explain для получения сводки плана запроса и статистики его выполнения:

Java

Query q = db.collection("employees").whereGreaterThan("salary",
100000).whereGreaterThan("experience", 0);

ExplainResults<QuerySnapshot> explainResults = q.explain(ExplainOptions.builder().analyze(true).build()).get();
ExplainMetrics metrics = explainResults.getMetrics();

PlanSummary planSummary = metrics.getPlanSummary();
ExecutionStats executionStats = metrics.getExecutionStats();

System.out.println(planSummary.getIndexesUsed());
System.out.println(stats.getResultsReturned());
System.out.println(stats.getExecutionDuration());
System.out.println(stats.getReadOperations());
System.out.println(stats.getDebugStats());

Node.js

let q = db.collection("employees")
      .where("salary", ">", 100000)
      .where("experience", ">",0);

let options = { analyze : 'true' };
let explainResults = await q.explain(options);

let planSummary = explainResults.metrics.planSummary;
let stats = explainResults.metrics.executionStats;

console.log(planSummary);
console.log(stats);

В следующем примере показано, как использование правильного порядка индексации уменьшает количество записей индекса, сканируемых Cloud Firestore .

Простые запросы

В приведенном выше примере с группой сотрудников простой запрос, использующий индекс (experience ASC, salary ASC) выглядит следующим образом:

Java

db.collection("employees")
  .whereGreaterThan("salary", 100000)
  .whereGreaterThan("experience", 0)
  .orderBy("experience")
  .orderBy("salary");

Запрос сканирует всего 95000 записей индекса и возвращает пять документов. Поскольку предикат запроса не выполняется, большое количество записей индекса считывается, но отфильтровывается.

// Output query planning info
{
    "indexesUsed": [
        {
            "properties": "(experience ASC, salary ASC, __name__ ASC)",
            "query_scope": "Collection"
        }
    ],

    // Output Query Execution Stats
    "resultsReturned": "5",
    "executionDuration": "2.5s",
    "readOperations": "100",
    "debugStats": {
        "index_entries_scanned": "95000",
        "documents_scanned": "5",
        "billing_details": {
            "documents_billable": "5",
            "index_entries_billable": "95000",
            "small_ops": "0",
            "min_query_cost": "0"
        }
    }
}

Исходя из экспертных знаний в данной области, можно заключить, что большинство сотрудников имеют хотя бы некоторый опыт работы, но лишь немногие получают зарплату выше 100 000. Исходя из этого, становится ясно, что ограничение salary более избирательно, чем ограничение experience . Чтобы повлиять на индекс, используемый Cloud Firestore для выполнения запроса, укажите предложение orderBy , которое ставит ограничение salary выше ограничения experience .

Java

db.collection("employees")
  .whereGreaterThan("salary", 100000)
  .whereGreaterThan("experience", 0)
  .orderBy("salary")
  .orderBy("experience");

При явном использовании предложения orderBy() для добавления предикатов Cloud Firestore использует индекс (salary ASC, experience ASC) для выполнения запроса. Поскольку селективность первого фильтра диапазона в этом запросе выше по сравнению с предыдущим запросом, запрос выполняется быстрее и является более экономичным.

// Output query planning info
{
    "indexesUsed": [
        {
            "properties": "(salary ASC, experience ASC, __name__ ASC)",
            "query_scope": "Collection"
        }
    ],

    // Output Query Execution Stats
    "resultsReturned": "5",
    "executionDuration": "0.2s",
    "readOperations": "6",
    "debugStats": {
        "index_entries_scanned": "1000",
        "documents_scanned": "5",
        "billing_details": {
            "documents_billable": "5",
            "index_entries_billable": "1000",
            "small_ops": "0",
            "min_query_cost": "0"
        }
    }
}

Что дальше?