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

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

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

Оптимизация запросов с помощью 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 записей индекса и возвращает пять документов. Поскольку предикат запроса не удовлетворен, большое количество записей индекса считывается, но отфильтровывается.

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

Что дальше