Query Explain позволяет отправлять запросы Cloud Firestore на сервер и получать подробную статистику по их выполнению. Она работает так же, как операция EXPLAIN [ANALYZE] во многих реляционных базах данных.
Запросы Query Explain можно отправлять с помощью клиентских библиотек сервера Firestore.
Результаты Query Explain помогают понять, как выполняются ваши запросы, показывая неэффективность и расположение вероятных узких мест на стороне сервера.
Объяснение запроса:
- Предоставляет статистику по этапу планирования запроса, чтобы вы могли скорректировать индексы запроса и повысить эффективность.
- С помощью функции анализа вы можете понять, сколько стоит каждый запрос и насколько он эффективен, а также быстро перебрать разные шаблоны запросов, чтобы оптимизировать их использование.
Варианты Query Explain: по умолчанию и анализ
Операции Query Explain можно выполнять с помощью параметра default или analyze.
По умолчанию Query Explain планирует запрос, но пропускает этап выполнения. Вы получите информацию об этапе планирования. Вы можете использовать это, чтобы проверить, есть ли в запросе необходимые индексы, и понять, какие индексы используются. Это поможет вам убедиться, например, что в определенном запросе используется составной индекс, а не пересечение множества разных индексов.
При использовании параметра analyze Query Explain планирует и выполняет запрос. В этом случае возвращается вся информация, упомянутая выше, а также статистика выполнения запроса. В нем будут содержаться платежные данные запроса, а также системная статистика по его выполнению. С помощью этого инструмента можно тестировать различные конфигурации запросов и индексов, чтобы оптимизировать их стоимость и задержку.
Сколько стоит Query Explain?
Если вы используете Query Explain с параметром по умолчанию, операции индексирования и чтения не выполняются. Независимо от сложности запроса, взимается плата за одну операцию чтения.
Когда вы используете Query Explain с параметром analyze, выполняются операции индексирования и чтения, поэтому с вас взимается плата за запрос, как обычно. За анализ не взимается дополнительная плата, только обычная плата за выполнение запроса.
Как использовать Query Explain с настройками по умолчанию
Чтобы отправить запрос на вариант по умолчанию, можно использовать клиентские библиотеки.
Обратите внимание, что запросы проходят аутентификацию с помощью IAM, используя те же разрешения, что и для обычных операций запроса. Другие методы аутентификации, например Firebase Authentication, игнорируются. Дополнительную информацию можно найти в руководстве IAM для серверных клиентских библиотек.
Java (Admin)
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();
Узел (администратор)
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;
Точный формат ответа зависит от среды выполнения. Возвращенные результаты можно преобразовать в JSON. Пример:
{
"indexes_used": [
{"query_scope": "Collection", "properties": "(category ASC, __name__ ASC)"},
{"query_scope": "Collection", "properties": "(country ASC, __name__ ASC)"},
]
}Подробную информацию вы найдете в справочном руководстве по отчету Query Explain.
Как использовать Query Explain с параметром analyze
Чтобы отправить запрос на анализ, можно использовать клиентские библиотеки.
Обратите внимание, что запросы проходят аутентификацию с помощью IAM, используя те же разрешения, что и для обычных операций запроса. Другие методы аутентификации, например Firebase Authentication, игнорируются. Дополнительную информацию можно найти в руководстве IAM для серверных клиентских библиотек.
Java (Admin)
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();
Узел (администратор)
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;
В примере ниже показан объект stats, возвращенный в дополнение к planInfo.
Точный формат ответа зависит от среды выполнения. Пример ответа в формате 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",
}
}
}Подробную информацию вы найдете в справочнике по отчету Query Explain.
Как интерпретировать результаты и вносить корректировки
Рассмотрим пример, в котором мы запрашиваем фильмы по жанру и стране производства.
Для иллюстрации предположим, что эквивалент этого SQL-запроса.
SELECT * FROM /movies WHERE category = 'Romantic' AND country = 'USA';
Если мы используем параметр analyze, возвращенные показатели показывают, что запрос выполняется по двум индексам с одним полем: (category ASC, __name__ ASC) и (country ASC, __name__ ASC). Он сканирует 16 500 записей индекса, но возвращает только 1200 документов.
// 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", } } }
Чтобы оптимизировать выполнение запроса, можно создать полностью покрытый составной индекс (category ASC, country ASC, __name__ ASC).
Если мы снова запустим запрос с параметром analyze, то увидим, что для этого запроса выбран только что созданный индекс и запрос выполняется намного быстрее и эффективнее.
// 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", } } }