Индексы являются важным фактором производительности базы данных. Подобно индексу книги, который сопоставляет темы в книге с номерами страниц, индекс базы данных сопоставляет элементы в базе данных с их местоположением в базе данных. Когда вы запрашиваете базу данных, база данных может использовать индекс для быстрого определения местоположения запрошенных вами элементов.
На этой странице описываются два типа индексов, которые использует 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-any для поля. |
Вектор | Поддерживает условия запроса FindNearest для поля. |
Области запроса
Каждый индекс ограничен либо коллекцией, либо группой коллекций. Это известно как область запроса индекса:
- Объем коллекции
- Cloud Firestore создает индексы с областью действия коллекции по умолчанию. Эти индексы поддерживают запросы, которые возвращают результаты из одной коллекции.
- Область действия группы сбора
- Группа коллекций включает все коллекции с тем же идентификатором коллекции. Чтобы выполнить запрос группы коллекций , который возвращает отфильтрованные или упорядоченные результаты из группы коллекций, необходимо создать соответствующий индекс с областью действия группы коллекций.
Порядок по умолчанию и поле __name__
В дополнение к сортировке документов по режимам индекса, указанным для каждого поля (по возрастанию или по убыванию), индексы применяют окончательную сортировку по полю __name__
каждого документа. Значение поля __name__
устанавливается на полный путь документа. Это означает, что документы в наборе результатов с одинаковыми значениями полей сортируются по пути документа.
По умолчанию поле __name__
сортируется в том же направлении, что и последнее отсортированное поле в определении индекса. Например:
Коллекция | Поля проиндексированы | Область запроса |
---|---|---|
города | __name__ | имя, Коллекция |
города | состояние __name__ | , Коллекция |
города | __name__ | страна, население, Коллекция |
Чтобы отсортировать результаты по направлению __name__
, отличному от направления по умолчанию, необходимо создать этот индекс.
Свойства индекса
Индекс, позволяющий выполнить запрос наиболее эффективно, определяется следующими свойствами:
- Поля, используемые в фильтрах равенства
- Поля, используемые в порядках сортировки
- Поля, используемые в фильтрах диапазона и неравенства (которые еще не включены в порядок сортировки)
- Поля, используемые в агрегациях (которые еще не включены в порядки сортировки и фильтры диапазона и неравенства)
Cloud Firestore вычисляет результаты запросов следующим образом:
- Определяет индекс, соответствующий коллекции запроса, свойствам фильтра, операторам фильтра и порядкам сортировки.
- Определяет позицию индекса, с которой начинается сканирование. Начальная позиция предваряется фильтрами равенства запроса и заканчивается фильтрами диапазона и неравенства в первом поле
orderBy
. - Начинает сканирование индекса, возвращая каждый документ, удовлетворяющий всем фильтрам, пока процесс сканирования не выполнит одно из следующих действий:
- Обнаруживает документ, который не соответствует условиям фильтра, и подтверждает, что любой последующий документ никогда не будет полностью соответствовать условиям фильтра.
- Достигает конца индекса.
- Собирает максимальное количество результатов, запрошенных запросом.
Пример индексации
Автоматически создавая для вас индексы с одним полем, 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
:
Коллекция | Поля проиндексированы | Область запроса |
---|---|---|
достопримечательности | категория | (или )Коллекция |
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
- city_name DESC
- температуры.лето ASC
- температуры.лето DESC
- температуры.зима ASC
- температуры.зима DESC
- Массив окрестностей содержит (ASC и DESC)
Композитные индексы
- city_name ASC, районы ARRAY
- city_name DESC, районы ARRAY
Индексные записи
Такая конфигурация индексации приводит к следующим записям индекса для документа:
Индекс | Индексированные данные |
---|---|
Записи индекса с одним полем | |
название_города ASC | city_name: "Сан-Франциско" |
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: "Сан-Франциско", районы: "Марина" |
city_name DESC, районы ARRAY | city_name: "Сан-Франциско", районы: "Миссия" |
city_name DESC, районы ARRAY | city_name: "Сан-Франциско", районы: "Центр города" |
city_name DESC, районы ARRAY | 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")
Вы можете создать индекс для каждого запроса:
Коллекция | Поля проиндексированы | Область запроса |
---|---|---|
рестораны | категория, рейтинг_звезд | Коллекция |
рестораны | город, рейтинг_звезд | Коллекция |
рестораны | категория, город, рейтинг_звезд | Коллекция |
рестораны | категория, город, выбор_редактора, рейтинг_звезд | Коллекция |
Лучшим решением будет сократить количество индексов, воспользовавшись возможностью Cloud Firestore объединять индексы для условий равенства:
Коллекция | Поля проиндексированы | Область запроса |
---|---|---|
рестораны | категория, рейтинг_звезд | Коллекция |
рестораны | город, рейтинг_звезд | Коллекция |
рестораны | выбор_редактора, рейтинг_звезд | Коллекция |
Этот набор индексов не только меньше, но и поддерживает дополнительный запрос:
db.collection("restaurants").where("editors_pick", "==", true) .orderBy("star_rating")
Ограничения индексации
Следующие ограничения применяются к индексам. Для получения дополнительной информации о квотах и ограничениях см. Квоты и ограничения .
Предел | Подробности |
---|---|
Максимальное количество составных индексов для базы данных |
|
Максимальное количество конфигураций одного поля для базы данных |
Одна конфигурация уровня поля может содержать несколько конфигураций для одного и того же поля. Например, исключение индексации одного поля и политика TTL для одного и того же поля считаются одной конфигурацией поля в отношении лимита. |
Максимальное количество записей индекса для каждого документа | 40,000 Количество записей индекса представляет собой сумму следующих значений для документа:
Чтобы увидеть, как Cloud Firestore преобразует документ и набор индексов в записи индекса, ознакомьтесь с этим примером подсчета записей индекса . |
Максимальное количество полей в составном индексе | 100 |
Максимальный размер записи индекса | 7,5 КБ Чтобы узнать, как Cloud Firestore вычисляет размер записи индекса, см. раздел Размер записи индекса . |
Максимальная сумма размеров записей индекса документа | 8 МБ Общий размер документа представляет собой сумму следующих параметров: |
Максимальный размер индексированного значения поля | 1500 байт Значения полей более 1500 байт усекаются. Запросы, включающие усеченные значения полей, могут возвращать противоречивые результаты. |
Лучшие практики индексирования
Для большинства приложений вы можете положиться на автоматическую индексацию и ссылки сообщений об ошибках для управления индексами. Однако вы можете захотеть добавить исключения для отдельных полей в следующих случаях:
Случай | Описание |
---|---|
Большие поля струн | Если у вас есть строковое поле, которое часто содержит длинные строковые значения, которые вы не используете для запросов, вы можете сократить расходы на хранение, исключив поле из индексации. |
Высокая скорость записи в коллекцию, содержащую документы с последовательными значениями | Если вы индексируете поле, которое последовательно увеличивается или уменьшается между документами в коллекции, например, временную метку, то максимальная скорость записи в коллекцию составляет 500 записей в секунду. Если вы не делаете запрос на основе поля с последовательными значениями, вы можете исключить поле из индексации, чтобы обойти это ограничение. Например, в случае использования Интернета вещей с высокой скоростью записи коллекция, содержащая документы с полем временной метки, может приблизиться к пределу в 500 записей в секунду. |
TTL-поля | Если вы используете политики TTL (время жизни) , обратите внимание, что поле TTL должно быть временной меткой. Индексация полей TTL включена по умолчанию и может повлиять на производительность при более высоких скоростях трафика. В качестве лучшей практики добавьте исключения для отдельных полей для ваших полей TTL. |
Большие массивы или поля карты | Большие массивы или поля карты могут приближаться к пределу в 40 000 записей индекса на документ. Если вы не делаете запрос на основе большого массива или поля карты, вам следует исключить его из индексации. |
Если вы используете запросы с операторами диапазона и неравенства для нескольких полей, ознакомьтесь с рекомендациями по индексации , которые следует учитывать для оптимизации производительности и стоимости запросов Cloud Firestore
Дополнительную информацию о том, как устранить проблемы индексации (разветвление индекса, ошибки INVALID_ARGUMENT
), см. на странице устранения неполадок .