Чтобы устранить неполадки с медленными запросами, используйте Query Explain. Этот инструмент позволяет получить план выполнения запроса и профиль выполнения во время работы. В следующем разделе описаны шаги, которые можно предпринять для оптимизации производительности запросов в зависимости от профиля выполнения:
Ограничение количества результатов
Чтобы определить, возвращает ли запрос много документов, используйте поле возвращенных записей в дереве выполнения. Попробуйте ограничить количество возвращаемых документов с помощью этапа limit(...). Это позволяет уменьшить размер сериализованных байтов в результатах, возвращаемых клиентам по сети. Если
узлу Limit предшествует узел MajorSort, механизм запросов может
объединить ихLimitMajorSort и заменить полную материализацию
в памяти и сортировку на сортировку TopN, снизив требования к памяти для
запроса.
Ограничение размера результирующего документа
Рекомендуем ограничить размер возвращаемого документа, используя select(...), чтобы возвращать только необходимые поля, или remove_fields(...), чтобы отбрасывать слишком большие поля. Это позволяет снизить затраты на вычисления и память при обработке промежуточных результатов и уменьшить размер сериализованных байтов результатов, возвращаемых клиентам по сети. В случаях, когда все поля, на которые ссылается запрос, охватываются обычным индексом, это также позволяет полностью охватить запрос сканированием индекса, избегая необходимости извлекать документы из основного хранилища.
Использование индексов
Чтобы настроить и оптимизировать индексы, следуйте инструкциям ниже.
Определите, использует ли запрос индекс.
Чтобы определить, использует ли запрос индекс, проверьте листовые узлы в дереве выполнения. Если конечный узел дерева выполнения – это узел TableScan, значит, запрос не использует индекс и сканирует документы из основного хранилища. Если используется индекс, в конечном узле дерева выполнения будут показаны идентификатор и поля индекса.
Определить лучший индекс
Индекс полезен для запроса, если он может уменьшить количество документов, которые механизм запросов должен получить из основного хранилища, или если порядок его полей может обеспечить требование сортировки запроса.
Если для запроса используется индекс, но механизм запросов по-прежнему извлекает и отбрасывает много документов, о чем свидетельствует узел сканирования, который возвращает много записей, за которым следует узел фильтра, который возвращает мало записей, это признак того, что предикат запроса, удовлетворяемый с помощью индекса, не является селективным. Чтобы создать более подходящий индекс, ознакомьтесь с разделом Создание индексов.
Если индекс используется для запроса, но механизм запросов по-прежнему выполняет переупорядочение набора результатов в памяти, что определяется узлом MajorSort в дереве выполнения запроса, это признак того, что используемый индекс не может быть использован для выполнения требования сортировки запроса. Чтобы создать более подходящий индекс, ознакомьтесь со следующим разделом.
Создание индексов
Следуйте инструкциям в документации по управлению индексами, чтобы создать индексы. Чтобы запрос мог использовать индексы, создайте обычные (не мультиключевые) индексы с полями в следующем порядке:
- Все поля, которые будут использоваться в операторах равенства. Чтобы повысить вероятность повторного использования в запросах, упорядочите поля в порядке убывания их встречаемости в операторах равенства в запросах.
- Все поля, по которым будет выполняться сортировка (в том же порядке).
- Поля, которые будут использоваться в операторах диапазона или неравенства в порядке убывания избирательности ограничений запроса.
- Поля, которые будут возвращены в составе запроса в индексе. Включение таких полей в индекс позволяет ему охватить запрос и избежать необходимости извлекать документ из основного хранилища.
Принудительное сканирование индекса или таблицы
При запросе Cloud Firestore автоматически использует любые индексы, которые могут повысить эффективность запроса. В результате вам не нужно
указывать индекс для своих запросов. Однако для запросов, критически важных для вашей рабочей нагрузки, мы рекомендуем использовать параметр forceIndex, чтобы обеспечить более стабильную производительность.
В некоторых случаях Cloud Firestore может выбрать индекс, который увеличивает задержку запроса. Если вы выполнили действия по устранению неполадок, связанных с регрессией производительности, и убедились, что для запроса имеет смысл попробовать другой индекс, вы можете указать индекс с помощью параметра forceIndex.
Вы можете использовать параметр forceIndex на любом этапе ввода в операциях конвейера, чтобы переопределить план запроса по умолчанию в Cloud Firestore и указать индекс, который нужно использовать, или принудительно выполнить сканирование таблицы.
Как принудительно задать определенный индекс
Чтобы принудительно использовать определенный индекс, укажите его идентификатор в виде строки в параметре forceIndex. Идентификатор индекса можно найти в консоли или в сообщениях об ошибках.
В следующем примере планировщик принудительно использует индекс с идентификатором CICAgOi36pgK:
Node.js
// Force Planner to use Index ID CICAgOi36pgK await db.pipeline() .collectionGroup({ collectionId: "customers", forceIndex: "CICAgOi36pgK" }) .limit(100) .execute();
Java
// Force Planner to use Index ID CICAgOi36pgK Pipeline.Snapshot results1 = firestore.pipeline() .collectionGroup("customers", new CollectionGroupOptions() .withHints(new CollectionHints().withForceIndex("CICAgOi36pgK"))) .limit(100) .execute().get();
Проложить маршрут
// Force Planner to use Index ID CICAgOi36pgK snapshot1 := client.Pipeline(). CollectionGroup("customers", firestore.WithForceIndex("CICAgOi36pgK")). Limit(100). Execute(ctx)
Вот несколько примеров использования принудительного индекса:
- Тестирование эффективности разных индексов.
- Обеспечение использования определенного, известного как оптимальный, индекса для запроса.
- Переопределение оптимизатора, когда его выбор по умолчанию неоптимален для конкретного запроса.
Если указанный индекс не найден, запрос завершается ошибкой.
Принудительное сканирование таблицы
При сканировании таблицы документы в коллекции или группе коллекций считываются без использования вторичных индексов. Чтобы принудительно запустить сканирование таблицы, задайте для параметра forceIndex значение primary.
В следующем примере принудительно выполняется сканирование таблицы:
// Force Planner to only do a Full-Table Scan
db.pipeline()
.collectionGroup({ collectionId: "customers", forceIndex: "primary" })
.limit(100)
Сканирование таблиц может быть полезно в следующих случаях:
- Для очень маленьких коллекций, где накладные расходы на индекс не оправданы.
- Для запросов, которые обращаются к большинству документов в коллекции.
- Для отладки и сравнения эффективности.
Как использовать forceIndex с Query Explain
Вы можете использовать Query Explain в режиме explain или analyze, чтобы наблюдать за эффектами forceIndex:
- Проверьте, что Cloud Firestore использовал указанный индекс в
forceIndex. Для этого найдите идентификатор индекса в конечных узлах дерева выполнения. - Убедитесь, что при использовании
forceIndex: "primary"в плане появляется узелTableScan. - В режиме
analyzeсравните показатели эффективности, такие как задержка, количество отсканированных документов и записей индекса, сforceIndexи без него, чтобы настроить производительность запросов.
Рекомендации для forceIndex
Хотя forceIndex обеспечивает больший контроль над выполнением запросов, оптимизатор запросов Cloud Firestore обычно эффективен для большинства вариантов использования.
При использовании forceIndex следуйте приведенным ниже рекомендациям.
- Используйте
forceIndexразумно. Если вы заметили, что план запросов по умолчанию работает неэффективно, используйте Query Explain, чтобы диагностировать проблему, прежде чем принудительно применять индекс. - При использовании
forceIndexобязательно тестируйте запросы с реалистичными объемами данных, чтобы понять их производительность и стоимость. - Не используйте
forceIndex: "primary"для больших коллекций в рабочих средах.
Дополнительную информацию о выходных данных запроса, выполненного с помощью Query Explain, можно найти в справочнике по выполнению запросов.