Catch up on highlights from Firebase at Google I/O 2023. Learn more

Типы индексов в Cloud Firestore

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

На этой странице описываются два типа индексов, которые использует Cloud Firestore: индексы с одним полем и составные индексы .

Индекс позади каждого запроса

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

Меньше управления индексами, больше разработки приложений

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

Типы индексов

Cloud Firestore использует два типа индексов: однопольные и составные . Помимо количества индексируемых полей, однополевые и составные индексы отличаются способом управления ими.

Индексы с одним полем

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

Автоматическое индексирование

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

  • Для каждого поля, не являющегося массивом и не относящимся к карте, Cloud Firestore определяет два индекса с одним полем области коллекции , один в восходящем режиме, а другой в нисходящем.

  • Для каждого поля карты Cloud Firestore создает следующее:

    • Один восходящий индекс области коллекции для каждого подполя, не являющегося массивом и не относящимся к карте.
    • Один нисходящий индекс области коллекции для каждого подполя, не являющегося массивом и не отображающим карту.
    • Один массив области коллекции содержит индекс для каждого подполя массива.
    • Cloud Firestore рекурсивно индексирует каждое подполе карты.
  • Для каждого поля массива в документе Cloud Firestore создает и поддерживает индекс массива в области коллекции.

  • Индексы с одним полем и областью действия группы сбора не поддерживаются по умолчанию.

Исключения для индекса с одним полем

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

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

Чтобы создать исключения для индекса с одним полем и управлять ими, см. раздел Управление индексами в Cloud Firestore .

Составные индексы

Составной индекс хранит отсортированное отображение всех документов в коллекции на основе упорядоченного списка полей для индексации.

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

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

Если вы попытаетесь выполнить указанный выше запрос без предварительного создания необходимого индекса, Cloud Firestore вернет сообщение об ошибке, содержащее ссылку, по которой вы можете перейти, чтобы создать отсутствующий индекс. Это происходит всякий раз, когда вы пытаетесь выполнить запрос, не поддерживаемый индексом. Вы также можете определять составные индексы и управлять ими вручную с помощью консоли или интерфейса командной строки Firebase . Дополнительные сведения о создании составных индексов и управлении ими см. в разделе Управление индексами .

Режимы индекса и области запроса

Вы настраиваете индексы с одним полем и составные индексы по-разному, но оба требуют настройки режимов индекса и областей запросов для ваших индексов.

Индексные режимы

Когда вы определяете индекс, вы выбираете режим индекса для каждого индексированного поля. Режим индекса каждого поля поддерживает определенные предложения запроса для этого поля. Вы можете выбрать один из следующих индексных режимов:

Индексный режим Описание
По возрастанию Поддерживает < , <= , == , >= , > , != , in и not-in , предложения запроса в поле и поддерживает сортировку результатов в порядке возрастания на основе этого значения поля.
По убыванию Поддерживает предложения запроса < , <= , == , >= , > , != , in и not-in в поле и поддерживает сортировку результатов в порядке убывания на основе значения этого поля.
Массив-содержит Поддерживает операторы запроса array-contains и array-contains-any в поле.

Области запроса

Каждый индекс относится либо к коллекции, либо к группе коллекций. Это известно как область запроса индекса:

Объем коллекции
Cloud Firestore по умолчанию создает индексы с областью коллекции. Эти индексы поддерживают запросы, которые возвращают результаты из одной коллекции.

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

Порядок по умолчанию и поле __name__

В дополнение к сортировке документов по режимам индекса, указанным для каждого поля (по возрастанию или по убыванию), индексы применяют окончательную сортировку по полю __name__ каждого документа. В поле __name__ устанавливается полный путь к документу. Это означает, что документы в результирующем наборе с одинаковыми значениями полей сортируются по пути к документу.

По умолчанию поле __name__ сортируется в том же направлении, что и последнее отсортированное поле в определении индекса. Например:

Коллекция Поля проиндексированы Область запроса
города имя, __name__ Коллекция
города состояние , __name__ Коллекция
города страна, население, __name__ Коллекция

Чтобы отсортировать результаты по направлению __name__ отличному от значения по умолчанию, вам необходимо создать этот индекс.

Пример индексации

Автоматически создавая для вас индексы с одним полем, Cloud Firestore позволяет вашему приложению быстро поддерживать самые простые запросы к базе данных. Индексы с одним полем позволяют выполнять простые запросы на основе значений полей и компараторов < , <= , == , >= , > и in . Для полей массива они позволяют выполнять запросы типа array-contains и array-contains-any .

Для иллюстрации рассмотрим следующие примеры с точки зрения создания индекса. Следующий фрагмент кода создает несколько документов city в коллекции cities и задает для каждого документа поля name , state , country , capital , population и tags :

Интернет
var citiesRef = db.collection("cities");

citiesRef.doc("SF").set({
    name: "San Francisco", state: "CA", country: "USA",
    capital: false, population: 860000,
    regions: ["west_coast", "norcal"] });
citiesRef.doc("LA").set({
    name: "Los Angeles", state: "CA", country: "USA",
    capital: false, population: 3900000,
    regions: ["west_coast", "socal"] });
citiesRef.doc("DC").set({
    name: "Washington, D.C.", state: null, country: "USA",
    capital: true, population: 680000,
    regions: ["east_coast"] });
citiesRef.doc("TOK").set({
    name: "Tokyo", state: null, country: "Japan",
    capital: true, population: 9000000,
    regions: ["kanto", "honshu"] });
citiesRef.doc("BJ").set({
    name: "Beijing", state: null, country: "China",
    capital: true, population: 21500000,
    regions: ["jingjinji", "hebei"] });

Предполагая настройки автоматического индексирования по умолчанию, Cloud Firestore обновляет один восходящий индекс с одним полем для каждого поля, не являющегося массивом, один нисходящий индекс с одним полем для каждого поля, не являющегося массивом, и один индекс с одним полем, содержащий массив, для поля массива. Каждая строка в следующей таблице представляет запись в индексе с одним полем:

Коллекция Поле проиндексировано Область запроса
города имя Коллекция
города состояние Коллекция
города страна Коллекция
города столица Коллекция
города население Коллекция
города имя Коллекция
города состояние Коллекция
города страна Коллекция
города столица Коллекция
города население Коллекция
города array-contains регионы Коллекция

Запросы, поддерживаемые индексами с одним полем

Используя эти автоматически созданные индексы с одним полем, вы можете выполнять простые запросы, подобные следующим:

Интернет
const stateQuery = citiesRef.where("state", "==", "CA");
const populationQuery = citiesRef.where("population", "<", 100000);
const nameQuery = citiesRef.where("name", ">=", "San Francisco");

Вы также можете in и составлять запросы на равенство ( == ):

Интернет
citiesRef.where('country', 'in', ["USA", "Japan", "China"])

// Compound equality queries
citiesRef.where("state", "==", "CO").where("name", "==", "Denver")
citiesRef.where("country", "==", "USA")
         .where("capital", "==", false)
         .where("state", "==", "CA")
         .where("population", "==", 860000)

Если вам нужно выполнить составной запрос, который использует сравнение диапазонов ( < , <= , > или >= ) или если вам нужно отсортировать по другому полю, вы должны создать составной индекс для этого запроса.

Индекс array-contains позволяет запрашивать поле массива regions :

Интернет
citiesRef.where("regions", "array-contains", "west_coast")
// array-contains-any and array-contains use the same indexes
citiesRef.where("regions", "array-contains-any", ["west_coast", "east_coast"])

Запросы, поддерживаемые составными индексами

Cloud Firestore использует составные индексы для поддержки составных запросов, которые еще не поддерживаются индексами с одним полем. Например, вам понадобится составной индекс для следующих запросов:

Интернет
citiesRef.where("country", "==", "USA").orderBy("population", "asc")
citiesRef.where("country", "==", "USA").where("population", "<", 3800000)
citiesRef.where("country", "==", "USA").where("population", ">", 690000)
// in and == clauses use the same index
citiesRef.where("country", "in", ["USA", "Japan", "China"])
         .where("population", ">", 690000)

Для этих запросов требуется составной индекс ниже. Поскольку в запросе используется равенство ( == или in ) для поля country , для этого поля можно использовать режим индекса по возрастанию или по убыванию. По умолчанию в предложениях о неравенстве применяется порядок сортировки по возрастанию на основе поля в предложении о неравенстве.

Коллекция Поля проиндексированы Область запроса
города (или ) страна, население Коллекция

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

Интернет
citiesRef.where("country", "==", "USA").orderBy("population", "desc")

citiesRef.where("country", "==", "USA")
         .where("population", "<", 3800000)
         .orderBy("population", "desc")

citiesRef.where("country", "==", "USA")
         .where("population", ">", 690000)
         .orderBy("population", "desc")

citiesRef.where("country", "in", ["USA", "Japan", "China"])
         .where("population", ">", 690000)
         .orderBy("population", "desc")
Коллекция Поля проиндексированы Область запроса
города страна, население Коллекция
города страна , население Коллекция

Вам также необходимо создать составной индекс для объединения запросов array-contains или array-contains-any с дополнительными предложениями.

Интернет
citiesRef.where("regions", "array-contains", "east_coast")
         .where("capital", "==", true)

// array-contains-any and array-contains use the same index
citiesRef.where("regions", "array-contains-any", ["west_coast", "east_coast"])
         .where("capital", "==", true)
Коллекция Поля проиндексированы Область запроса
города массив-содержит теги, заглавная (или ) Коллекция

Запросы, поддерживаемые индексами группы сбора

Чтобы продемонстрировать индекс с областью действия группы коллекции, представьте, что вы добавляете подколлекцию landmarks в некоторые документы city :

Интернет
var citiesRef = db.collection("cities");

citiesRef.doc("SF").collection("landmarks").doc().set({
    name: "Golden Gate Bridge",
    category : "bridge" });
citiesRef.doc("SF").collection("landmarks").doc().set({
    name: "Golden Gate Park",
    category : "park" });

citiesRef.doc("DC").collection("landmarks").doc().set({
    name: "National Gallery of Art",
    category : "museum" });
citiesRef.doc("DC").collection("landmarks").doc().set({
    name: "National Mall",
    category : "park" });

Используя следующий индекс с одним полем и областью коллекции, вы можете запросить коллекцию landmarks одного города на основе поля category :

Коллекция Поля проиндексированы Область запроса
landmarks Категория (или ) Коллекция
Интернет
citiesRef.doc("SF").collection("landmarks").where("category", "==", "park")
citiesRef.doc("SF").collection("landmarks").where("category", "in", ["park", "museum"])

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

Коллекция Поля проиндексированы Область запроса
landmarks Категория (или ) Группа сбора

Если этот индекс включен, вы можете запросить группу сбора landmarks :

Интернет
var landmarksGroupRef = db.collectionGroup("landmarks");

landmarksGroupRef.where("category", "==", "park")
landmarksGroupRef.where("category", "in", ["park", "museum"])

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

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

Интернет
db.collectionGroup("landmarks").get()

Записи указателя

Настроенные индексы вашего проекта и структура документа определяют количество записей индекса для документа. Элементы указателя учитываются в соответствии с ограничением количества элементов указателя .

В следующем примере демонстрируются элементы указателя документа.

Документ

/cities/SF

city_name : "San Francisco"
temperatures : {summer: 67, winter: 55}
neighborhoods : ["Mission", "Downtown", "Marina"]

Однополевые индексы

  • имя_города АСЦ
  • имя_города DESC
  • температура.лето ASC
  • температуры.лето DESC
  • температура.зима ASC
  • температура.зима DESC
  • массив окрестностей содержит (ASC и DESC)

Составные индексы

  • city_name ASC, районы ARRAY
  • имя_города DESC, районы МАССИВ

Записи указателя

Эта конфигурация индексирования приводит к следующим 18 элементам индекса для документа:

Индекс Индексированные данные
Записи индекса с одним полем
имя_города АСЦ city_name: "Сан-Франциско"
имя_города DESC city_name: "Сан-Франциско"
температура.лето ASC температура.лето: 67
температуры.лето DESC температура.лето: 67
температура.зима ASC температура.зима: 55
температура.зима DESC температура.зима: 55
массив окрестности Содержит ASC окрестности: "Миссия"
окрестности Массив Содержит DESC окрестности: "Миссия"
массив окрестности Содержит ASC районы: «Центр города»
окрестности Массив Содержит DESC районы: «Центр города»
массив окрестности Содержит ASC районы: "Марина"
окрестности Массив Содержит DESC районы: "Марина"
Элементы составного указателя
city_name ASC, районы ARRAY city_name: "Сан-Франциско", районы: "Миссия"
city_name ASC, районы ARRAY city_name: "Сан-Франциско", районы: "Даунтаун"
city_name ASC, районы ARRAY city_name: "Сан-Франциско", районы: "Марина"
имя_города DESC, районы МАССИВ city_name: "Сан-Франциско", районы: "Миссия"
имя_города DESC, районы МАССИВ city_name: "Сан-Франциско", районы: "Даунтаун"
имя_города DESC, районы МАССИВ city_name: "Сан-Франциско", районы: "Марина"

Индексы и цены

Индексы увеличивают затраты на хранение вашего приложения. Дополнительные сведения о том, как рассчитывается размер хранилища для индексов, см. в разделе Размер элемента индекса .

Использование слияния индексов

Хотя Cloud Firestore использует индекс для каждого запроса, не обязательно требуется один индекс для каждого запроса. Для запросов с несколькими предложениями равенства ( == ) и, при необходимости, предложением orderBy Cloud Firestore может повторно использовать существующие индексы. Cloud Firestore может объединять индексы для простых фильтров равенства, чтобы создавать составные индексы, необходимые для более крупных запросов на равенство.

Вы можете снизить затраты на индексирование, определив ситуации, в которых можно воспользоваться слиянием индексов. Например, представьте коллекцию restaurants для приложения для оценки ресторанов:

  • рестораны

    • name : "Burger Thyme"
      category : "burgers"
      city : "San Francisco"
      editors_pick : true
      star_rating : 4

Теперь представьте, что это приложение использует запросы, подобные приведенным ниже. Обратите внимание, что приложение использует комбинации предложений равенства для category , city и editors_pick , всегда сортируя по возрастанию star_rating :

Интернет
db.collection("restaurants").where("category", "==", "burgers")
                            .orderBy("star_rating")

db.collection("restaurants").where("city", "==", "San Francisco")
                            .orderBy("star_rating")

db.collection("restaurants").where("category", "==", "burgers")
                            .where("city", "==", "San Francisco")
                            .orderBy("star_rating")

db.collection("restaurants").where("category", "==", "burgers")
                            .where("city", "==" "San Francisco")
                            .where("editors_pick", "==", true )
                            .orderBy("star_rating")

Вы можете создать индекс для каждого запроса:

Коллекция Поля проиндексированы Область запроса
рестораны Категория , рейтинг star_rating Коллекция
рестораны город, звездный_рейтинг Коллекция
рестораны категория, город, звездный_рейтинг Коллекция
рестораны категория, город, editors_pick, star_rating Коллекция

В качестве лучшего решения вы можете уменьшить количество индексов, воспользовавшись возможностью Cloud Firestore объединять индексы для условий равенства:

Коллекция Поля проиндексированы Область запроса
рестораны Категория , рейтинг star_rating Коллекция
рестораны город, звездный_рейтинг Коллекция
рестораны editors_pick, star_rating Коллекция

Этот набор индексов не только меньше, но и поддерживает дополнительный запрос:

Интернет
db.collection("restaurants").where("editors_pick", "==", true)
                            .orderBy("star_rating")

Ограничения индексации

К индексам применяются следующие ограничения. Все квоты и лимиты см. в разделе Квоты и лимиты .

Ограничение Подробности
Максимальное количество составных индексов для базы данных

200

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

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

200

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

Максимальное количество записей указателя для каждого документа

40 000

Количество элементов указателя представляет собой сумму следующих значений для документа:

  • Количество записей индекса с одним полем
  • Количество записей составного индекса

Чтобы увидеть, как Cloud Firestore превращает документ и набор индексов в записи индекса, см . этот пример подсчета записей индекса .

Максимальное количество полей в составном индексе 100
Максимальный размер записи индекса

7,5 КиБ

Чтобы узнать, как Cloud Firestore вычисляет размер элемента индекса, см. Размер элемента индекса .

Максимальная сумма размеров записей указателя документа

8 МБ

Общий размер представляет собой сумму следующих значений для документа:

  • Сумма размеров записей индекса с одним полем документа.
  • Сумма размеров элементов составного индекса документа
  • Максимальный размер значения индексированного поля

    1500 байт

    Значения полей более 1500 байт обрезаются. Запросы, включающие усеченные значения полей, могут возвращать противоречивые результаты.

    Лучшие практики индексирования

    Для большинства приложений вы можете полагаться на автоматическое индексирование и ссылки на сообщения об ошибках для управления вашими индексами. Однако вы можете добавить исключения для одного поля в следующих случаях:

    Случай Описание
    Большие строковые поля

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

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

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

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

    Поля TTL

    Если вы используете политики TTL (время жизни) , обратите внимание, что в поле TTL должна быть отметка времени. Индексирование полей TTL включено по умолчанию и может повлиять на производительность при более высоких скоростях трафика. Рекомендуется добавить исключения для отдельных полей для полей TTL.

    Большой массив или поля карты

    Поля больших массивов или карт могут приближаться к лимиту в 40 000 записей указателя на документ. Если вы не выполняете запрос на основе большого массива или поля карты, вы должны исключить его из индексации.

    Для получения дополнительной информации о том, как решить проблемы с индексированием (разветвление индекса, ошибки INVALID_ARGUMENT ), посетите страницу устранения неполадок .