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

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

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

Оптимизация запросов с помощью Query Объяснение

Чтобы определить, являются ли используемый запрос и индексы оптимальными, вы можете использовать Query Объяснение, чтобы получить сводку плана запроса и статистику выполнения запроса:

Джава

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) выглядит следующим образом:

Джава

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

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

// 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 .

Джава

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"
        }
    }
}

Что дальше