Типы индексов в 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 создает и поддерживает индекс, содержащий массив, в пределах всей коллекции.

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

Исключения для индексов, содержащих одно поле

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

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

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

Для создания и управления исключениями для индексов, содержащих одно поле, см. раздел «Управление индексами» .

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

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

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

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

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

Вы также можете определять и управлять составными индексами вручную с помощью консоли или Firebase CLI . Дополнительную информацию о создании и управлении составными индексами см. в разделе «Управление индексами» .

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

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

Режимы индексации

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

Режим индексации Описание
Восходящая Поддерживает условия запроса < , <= , == , >= , > , != , in , и not-in для данного поля, а также сортировку результатов в порядке возрастания на основе значения этого поля.
вниз Поддерживает условия запроса < , <= , == , >= , > , != , in , и not-in для данного поля, а также сортировку результатов в порядке убывания на основе значения этого поля.
Array‑contains Поддерживает условия запроса array-contains и array-contains-any для данного поля.
Вектор Поддерживает условия запроса FindNearest для данного поля.

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

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

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

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

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

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

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

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

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

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

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

  • Поля, используемые в фильтрах равенства
  • Поля, используемые в порядке сортировки
  • Поля, используемые в фильтрах диапазона и неравенства (которые еще не включены в порядок сортировки).
  • Поля, используемые в агрегациях (которые еще не включены в порядок сортировки, а также в фильтры диапазона и неравенства).

Cloud Firestore вычисляет результаты запросов следующим образом:

  1. Определяет индекс, соответствующий коллекции запроса, свойствам фильтра, операторам фильтра и порядку сортировки.
  2. Определяет позицию индекса, с которой начинается сканирование. Начальная позиция предваряется фильтрами равенства запроса и заканчивается фильтрами диапазона и неравенства по первому полю orderBy .
  3. Начинается сканирование индекса, возвращая каждый документ, удовлетворяющий всем фильтрам, до тех пор, пока процесс сканирования не выполнит одно из следующих действий:
    • Обнаружен документ, не соответствующий условиям фильтра, и подтверждается, что любой последующий документ никогда не будет полностью соответствовать условиям фильтра.
    • Достиг конца указателя.
    • Собирает максимальное количество результатов, запрошенных запросом.

Пример индексирования

Автоматически создавая индексы для отдельных полей, 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)
Коллекция Индексированные поля Область запроса
города array-contains tags, (or ) capital Коллекция

Запросы, поддерживаемые индексами групп коллекций.

Чтобы продемонстрировать индекс с областью охвата групп коллекций, добавьте подколлекцию 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 :

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

Например, если вас интересует поиск достопримечательностей во всех городах, выполните следующий запрос к группе коллекций, которая включает все коллекции 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"]

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

  • название города ASC
  • название города DESC
  • температуры.лето ASC
  • температура.лето DESC
  • температура.зима ASC
  • температура.зима DESC
  • массив neighborhoods содержит (ASC и DESC)

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

  • city_name ASC, neighborhoods ARRAY
  • city_name DESC, neighborhoods ARRAY

Указательные записи

В результате такой конфигурации индексирования для документа будут созданы следующие записи:

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

Индексы и ценообразование

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

Используйте слияние индексов.

Хотя 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")

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

Коллекция Индексированные поля Область запроса
рестораны category, star_rating Коллекция
рестораны city, star_rating Коллекция
рестораны category, city, star_rating Коллекция
рестораны category, city, editors_pick, star_rating Коллекция

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

Коллекция Индексированные поля Область запроса
рестораны category, star_rating Коллекция
рестораны city, star_rating Коллекция
рестораны editors_pick, star_rating Коллекция

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

Веб
db.collection("restaurants").where("editors_pick", "==", true)
                            .orderBy("star_rating")

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

К индексам применяются следующие ограничения. Дополнительную информацию о квотах и ​​ограничениях см. в разделе «Квоты и ограничения» .

Лимит Подробности
Максимальное количество составных индексов для базы данных
Максимальное количество конфигураций с одним полем для базы данных
  • Код ошибки 200 появляется, если вы не включили выставление счетов для своего проекта Google Cloud .

    Если вам требуется больше квоты, необходимо включить оплату для вашего проекта Google Cloud .

  • 1000 при включении оплаты для вашего проекта Google Cloud .

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

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

40 000

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

  • Количество записей в индексе, содержащих одно поле.
  • Количество записей в составном индексе

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

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

7,5 КиБ

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

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

8 МиБ

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

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

    1500 байт

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

    Передовые методы индексирования

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

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

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

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

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

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

    Поля TTL

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

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

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

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

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