Обычная реляционная база на одном сервере закрывает большинство задач. Но когда нужна гибкая схема, огромный масштаб или глобальное распространение, у GCP есть отдельные базы под эти случаи. Разберём три главные и когда брать их вместо Cloud SQL.

Cloud SQL заказ JOIN покупатель Firestore документ заказа с именем покупателя один запрос

В документной базе нет соединений, поэтому имя покупателя дублируют в документ заказа и читают список одним запросом. Место дешёвое, а обращения платные, и настоящая работа это решить, что делать с копией, когда источник изменился.

Обязательно

Firestore

У каждого пользователя свой набор полей в профиле, и они всё время меняются — под жёсткую схему таблиц такое не ложится. Firestore — управляемая документная база: данные хранятся как JSON-подобные документы, собранные в коллекции, а не как строки в таблицах. Её главные черты — serverless (не думаете о серверах и мощности, платите за операции и хранение, масштабируется сама) и удобство для приложений: гибкая схема, запросы по полям, а в мобильных и веб-клиентах — синхронизация в реальном времени и работа офлайн.

Firestore — выбор по умолчанию, когда нужна NoSQL в GCP: пользовательские профили, настройки, каталоги, чаты, состояние приложений. Ближайший аналог в AWS — DynamoDB, но Firestore богаче по запросам и заточен под клиентскую синхронизацию.

Первое решение принимают ещё до первой строчки кода: у Firestore два режима — Native и Datastore, и режим выбирают один раз, при создании базы. Datastore-режим оставлен для старых приложений: база в нём принимает запросы Datastore API и отказывает запросам Firestore API. Галочкой это потом не переключается, так что для нового сервиса берут Native. Ошибку иначе обнаружите не в момент создания базы, а когда не заработает нужная библиотека, — и удивитесь, потому что «база же есть».

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

У «раскладывать под запросы» есть границы, и их лучше знать заранее:

  • документ — до 1 МиБ. Складывать в один документ растущий список (скажем, все заказы клиента) нельзя: однажды он упрётся в потолок, и упрётся в бою;
  • горячий документ. Часто писать в один и тот же документ не выйдет. Ориентир, который Google называл раньше, — около одной записи в секунду; сейчас точной цифры в документации нет и советуют замерять под своей нагрузкой, но суть не изменилась. Счётчик просмотров в одном документе — классический способ упереться в стену: его разносят по нескольким документам и складывают при чтении;
  • последовательные значения в индексе. Если индексируемое поле растёт монотонно (например, метка времени), запись во всю коллекцию упирается примерно в 500 операций в секунду;
  • разгон. Новую коллекцию не заливают сразу на полную: правило «500/50/5» — начать с 500 операций в секунду и повышать нагрузку на 50% каждые пять минут.

И два счёта, которые выставят именно вам. Первый: запрос сразу по нескольким полям требует составного индекса, и завести его нужно заранее — без него запрос не выполнится вовсе (Firestore в ошибке подскажет, какой именно индекс нужен). Второй: платите вы за операции — за каждый прочитанный, записанный и удалённый документ, а не за время работы сервера. Отсюда и растут «неудобные и дорогие выборки»: то, что в SQL было одним запросом с джойном, здесь превращается в сотни чтений документов, и каждое из них попадает в счёт.

Денормализация: как это выглядит

«Раскладывают под запросы» — главное умение при работе с документной базой, и его проще показать.

В реляционной базе список заказов с именем покупателя — это соединение двух таблиц. В документной соединений нет вовсе, значит имя покупателя дублируют в документ заказа:

// коллекция orders, документ ord-10432
{
  "customerId": "cust-77",
  "customerName": "Иван Петров",        // дубль из документа покупателя
  "status": "PAID",
  "total": 8970,
  "createdAt": "2026-09-25T11:04:00Z"
}

Теперь список заказов рисуется одним запросом, без второго обращения. Это и есть денормализация: место дешёвое, а обращения дорогие (за них и платят), поэтому данные дублируют под тот экран, который их показывает.

Что при этом надо решить — и это настоящая работа:

Что делать при изменении источника. Покупатель сменил имя — в старых заказах остаётся прежнее. Иногда это правильно (в чеке должно быть имя на момент покупки), иногда нет (карточка клиента). Для второго случая нужен обход и обновление копий — и его пишут заранее, а не когда обнаружат расхождение.

Что дублировать, а что нет. Дублируют то, что показывается вместе с документом и меняется редко: имя, название товара, цену на момент покупки. Не дублируют то, что меняется часто и должно быть одинаковым везде (остаток на складе, статус доставки) — за таким ходят в источник.

Как считать агрегаты. Число заказов покупателя в документной базе не считается запросом дёшево: это чтение всех документов. Поэтому счётчики держат полем и обновляют при записи (в Firestore для этого есть атомарное увеличение), а не пересчитывают каждый раз.

Практический порядок работы: сначала выписать экраны и запросы, потом спроектировать документы под них, и только потом писать код. Обратный порядок («сделаем как в реляционной, потом разложим») заканчивается переделкой модели.

Bigtable

Тысяча устройств пишут метрику каждую секунду, и через год это миллиарды строк, которые надо читать по ключу за миллисекунды. Bigtable — база другого класса: широко-колоночное хранилище (wide-column) для очень больших объёмов и очень высокой пропускной способности с предсказуемо низкой задержкой. Её берут под потоковые и аналитические нагрузки: временные ряды, метрики, события интернета вещей, данные для аналитики. Порядок цифр стоит держать в голове: один узел Bigtable тянет порядка десяти-семнадцати тысяч операций в секунду, а масштабируют базу добавлением узлов. То есть «миллионы операций в секунду» — это не свойство сервиса, а сотни узлов и соответствующий счёт. Для обычного backend-сервиса это избыточно; Bigtable оправдывает себя на действительно больших потоках.

Spanner

Spanner — база, которая совмещает то, что обычно приходится выбирать: она даёт и SQL с транзакциями и согласованностью, как у реляционной базы, и горизонтальный масштаб с глобальным распространением, как у NoSQL. То есть вы работаете с привычными таблицами, SQL и ACID-транзакциями, но без потолка одного сервера и с возможностью растянуться на несколько регионов мира.

Звучит как магия, но под этим лежит конкретный механизм — TrueTime, служба точного времени на атомных часах и приёмниках GPS в дата-центрах Google. Она возвращает не «время», а интервал с гарантированной погрешностью: «сейчас между вот этим и вот этим моментом». Зная предел ошибки, Spanner умеет упорядочить транзакции из разных регионов так, будто они шли по очереди в одной базе. Отсюда и главное свойство — внешняя согласованность: если одна транзакция завершилась раньше другой, все читатели увидят их именно в этом порядке, в каком бы регионе ни спрашивали.

За это платят: Spanner сложнее обычной базы и дороже, хотя порог входа заметно снизился — раньше минимальной покупкой был целый узел, а сейчас мощность берут порциями по 100 единиц обработки, это десятая часть узла. Берут его, когда действительно нужен глобальный масштаб с реляционной семантикой — крупные финансовые и торговые системы, глобальные каталоги. Для сервиса, который помещается на один сервер, это из пушки по воробьям.

Что выбрать

  • Cloud SQL (PostgreSQL) — классическое приложение, реляционная модель, джойны, данные на одном сервере. Разумный выбор по умолчанию.
  • Firestore — нужна гибкая документная модель, serverless и синхронизация с клиентами; большинство NoSQL-задач.
  • Bigtable — гигантские потоки данных с низкой задержкой (метрики, временные ряды, аналитика).
  • Spanner — нужен глобальный масштаб с полноценным SQL и транзакциями.

Практический совет новичку: не берите Firestore или Spanner «на будущее». Если данные спокойно живут на одном сервере и нужны джойны — Cloud SQL проще и дешевле. Специализированные базы оправдывают себя там, где обычная упирается в потолок.

Где это применяется

Эти базы закрывают ниши, куда не дотягивается обычная реляционная: гибкая документная модель и клиентская синхронизация (Firestore), гигантские потоки (Bigtable), глобальный масштаб с SQL (Spanner). В связке с serverless Firestore особенно естественна: функция без сервера + база без сервера дают систему, тарифицируемую по факту.

Типичные ошибки новичков:

  • берут Firestore или Spanner для маленького сервиса — там, где Cloud SQL проще и богаче;
  • ждут от Firestore привычного SQL с джойнами — это другая модель доступа;
  • плохо проектируют под запросы — и упираются в неудобные и дорогие выборки.
Дополнительно: при первом чтении можно пропустить

Глубже: Bigtable: всё решает ключ строкирасширенное

Про Bigtable можно сказать одну вещь, и она важнее остальных: судьба таблицы определяется конструкцией ключа строки. Всё остальное — детали.

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

Хорошо: чтение диапазона. Если ключ начинается с идентификатора устройства, а дальше идёт время, то «все измерения устройства за сутки» — это чтение одного непрерывного диапазона, то есть максимально быстрая операция.

Плохо: горячая область. Если ключ начинается со времени (2026-09-25T11:04#device-7), то все новые записи идут в конец таблицы, то есть в одну область на одном узле. Сколько бы узлов вы ни добавили, писать будет один — это называют горячей точкой, и это главная причина, по которой Bigtable «не масштабируется».

Как строят ключ, чтобы этого не было:

  • Сначала то, что распределяет (идентификатор устройства, пользователя, арендатора), потом время: device-7#2026-09-25T11:04.
  • Если естественного распределителя нет, добавляют вычисляемый префикс — например, остаток от хеша идентификатора (03#device-7#...). Это размазывает запись по областям, ценой того, что «прочитать все записи по порядку» становится дороже.
  • Обратный отсчёт времени (вместо метки — разность с большим числом), если нужны последние записи первыми: тогда свежие данные оказываются в начале диапазона.
  • Ключ короткий, потому что он хранится в каждой ячейке.

Ещё два практических свойства. Bigtable любит высокие и узкие таблицы: много строк, мало столбцов, а не наоборот. И у него нет запросов по значению: единственный способ найти данные — по ключу или по диапазону ключей, то есть вторичных индексов нет вовсе, и всё, что нужно искать, попадает в ключ.

Отсюда и область применения: временные ряды, события, показания датчиков, поведение пользователей — там, где данные приходят потоком и читаются диапазонами. И порог входа: минимальная установка стоит заметных денег (платят за узлы круглосуточно), поэтому для небольших объёмов её не берут.

Глубже: аналитика: BigQueryрасширенное

В списке «других баз» не хватает главного участника, ради которого GCP часто и выбирают: BigQuery — хранилище для аналитики. Это не замена базе приложения, а место, куда уезжают отчёты.

Зачем он нужен именно рядом с этими базами. Отчёт «выручка по категориям за год» в документной базе невозможен (нет соединений и агрегатов по большим объёмам), в реляционной он выполняется и мешает работе приложения. В хранилище для аналитики он считается за секунды, потому что данные лежат по столбцам и запрос читает только нужные.

Как данные туда попадают:

  • Выгрузка из Firestore — штатная операция экспорта, которую можно запускать по расписанию;
  • Поток изменений — лента изменений документной базы или журнал транзакций реляционной, через готовую службу переноса;
  • Прямые запросы к внешним данным — BigQuery умеет читать файлы в хранилище объектов и данные в некоторых базах без переноса вовсе;
  • Потоковая вставка — события пишутся в хранилище сразу, из очереди.

Что важно про цену: платят за объём просканированных данных в запросе (или за выделенные вычислительные ресурсы, если объём большой и предсказуемый). Порядок — единицы долларов за терабайт сканирования. Отсюда практика: таблицы секционируют по дате и кластеризуют по частым фильтрам, а в запросах не пишут SELECT * — иначе один неаккуратный запрос по большой таблице стоит заметных денег.

И правило, которое отвечает на вопрос из следующего раздела: как только в приложении появляются отчёты и аналитика, их уводят сюда, а не пытаются посчитать в базе приложения. Это же снимает половину вопросов «Firestore перестал подходить».

Глубже: когда Firestore перестаёт подходитьрасширенное

Документная база хороша, пока запросы простые и известны заранее. Признаки, что вы выросли из неё:

Понадобились агрегаты и отчёты. «Сумма заказов по регионам за квартал» в документной базе — это чтение всех документов и плата за каждое. Ответ: считать агрегаты при записи (счётчики полями) для того, что нужно постоянно, и уводить отчётность в аналитическое хранилище для всего остального.

Запросы стали непредсказуемыми. Бизнес просит фильтровать по любому набору полей — а в документной базе каждый новый вид запроса требует своего составного индекса, и число их растёт. Здесь либо реляционная база, либо поисковый индекс рядом.

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

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

Что делают вместо переписывания с нуля: разделяют по видам данных. Оперативные документы, которые читаются по ключу, остаются в документной базе; реляционные связи и отчёты уезжают в реляционную базу и в аналитическое хранилище. Это обычная зрелая схема, и она дешевле попытки уложить всё в одно хранилище.

Коротко

  • Firestore это выбор по умолчанию для NoSQL в GCP: документы и коллекции, гибкая схема, синхронизация с клиентами; режим Native или Datastore выбирают один раз при создании.
  • Границы знают заранее: документ до 1 МиБ, горячий документ не выдержит частой записи, монотонное поле в индексе упирается около 500 операций в секунду, новую коллекцию разгоняют по правилу 500/50/5, запрос по нескольким полям требует составного индекса.
  • Денормализация это дублирование под экран: имя покупателя копируют в заказ, решают, что делать при смене источника, и держат счётчики полями, потому что агрегаты это чтение всех документов.
  • Bigtable решает всё ключом строки: сначала то, что распределяет, потом время; ключ со временем впереди даёт горячую область на одном узле; запросов по значению нет.
  • Spanner даёт SQL с транзакциями и горизонтальный масштаб через TrueTime, а покупают его порциями по 100 единиц обработки.
  • Cloud SQL по умолчанию, Firestore для документной модели, Bigtable для потоков, Spanner для глобального SQL; «на будущее» специализированные базы не берут.
  • Отчёты и аналитику уводят в BigQuery через экспорт, поток изменений, внешние таблицы или потоковую вставку; платят за просканированное.
  • Из Firestore вырастают, когда понадобились агрегаты, непредсказуемые запросы, транзакции между многими документами или счёт вырос от чтений; тогда данные разделяют по видам, а не переписывают с нуля.

Что почитать дальше