---
metadata:
  - name: generator
    content: Diplodoc Platform v5.50.4
alternate:
  - https://ydb.tech/docs/en/faq/all.md
  - https://ydb.tech/docs/ru/faq/all.md
sourcePath: ru/core/faq/all.md
---
> **Documentation Index:** Fetch the complete configuration index at https://ydb.tech/docs/ru/llms.txt

<!-- source: ru/faq/_includes/all.md -->
# Все вопросы на одной странице

## Общие вопросы {#common}

<!-- source: ru/faq/common.md -->
<!-- source: ru/faq/_includes/common.md -->
# Общие вопросы про YDB

## Что такое YDB? {#what-is-ydb}

YDB — это распределенная отказоустойчивая Distributed SQL СУБД. YDB обеспечивает высокую доступность и масштабируемость, и, в то же время, строгую консистентность и поддержку ACID-транзакций. Для запросов используется диалект SQL (YQL).

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

## Какие возможности предоставляет YDB? {#ydb-features}

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

## Какая модель консистентности используется в YDB? {#ydb-consistency}

Для чтения данных YDB использует модель строгой консистентности (непротиворечивости) данных.

## Как проектировать первичный ключ? {#create-pk}

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

* Необходимо избегать ситуаций, когда основная часть нагрузки приходится на одну [партицию](https://ydb.tech/docs/ru/concepts/datamodel/table.md#partitioning) таблицы. При равномерной нагрузке проще достигается высокая общая производительность.

  Как следствие этого правила, не стоит в качестве первичного ключа таблицы использовать монотонно возрастающую последовательность, например, timestamp.
* Чем меньше партиций таблиц будет задействовано во время исполнения запроса, тем быстрее он будет исполнен. Чтобы достичь большей производительности стоит руководствоваться правилом: один запрос — одна партиция.
* Необходимо избегать ситуаций, при которых какая-то малая часть БД нагружена существенно больше, чем остальные части БД.

Подробнее читайте в разделе [Выбор первичного ключа](https://ydb.tech/docs/ru/dev/primary-key/index.md).

## Как равномерно распределить нагрузку по партициям таблицы? {#balance-shard-load}

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

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

Подробнее читайте в разделе [Выбор первичного ключа](https://ydb.tech/docs/ru/dev/primary-key/index.md).

## Можно ли использовать NULL в ключевой колонке? {#null}

В YDB все колонки, включая ключевые, могут содержать значение `NULL`, однако использовать `NULL` в качестве значений в ключевых колонках не рекомендуется.

По стандарту языка SQL (ISO/IEC 9075) значение `NULL` нельзя сравнивать с другими значениями, вследствие чего использование лаконичных конструкций SQL с простыми операторами сравнения может приводить, например, к тому, что строки, содержащие значение NULL, могут быть пропущены при фильтрации.

## Существует ли оптимальный размер строки базы данных? {#string-size}

Для достижения высокой производительности не рекомендуется записывать в БД строки размером более 8 МБ и ключевые колонки размером более 2 КБ.

Подробнее существующие ограничения описаны в разделе [Ограничения базы данных](https://ydb.tech/docs/ru/concepts/limits-ydb.md).

## Как работают вторичные индексы в YDB? {#secondary_indexes}

Вторичные индексы в YDB — глобальные и могут быть неуникальными.

Подробнее читайте в разделе [Вторичные индексы](https://ydb.tech/docs/ru/concepts/query_execution/secondary_indexes.md).

## Как осуществляется постраничный вывод? {#paging}

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

Подробнее читайте в разделе [Постраничный вывод](https://ydb.tech/docs/ru/dev/paging.md).

## Как удалять устаревшие данные? {#ttl}

Для эффективного удаления устаревших данных рекомендуется использовать [TTL](https://ydb.tech/docs/ru/concepts/ttl.md).

## Как происходит синхронизация данных между дата-центрами в геораспределенных кластерах {#sinc-between-dc}

[Таблетка](https://ydb.tech/docs/ru/concepts/glossary.md#tablet)-лидер записывает данные в [распределенное сетевое хранилище](https://ydb.tech/docs/ru/concepts/glossary.md#distributed-storage), которое сохраняет копии в нескольких дата-центрах. YDB подтверждает пользователю запрос только после успешного сохранения нужного числа копий в нужном числе дата-центров.
<!-- endsource: ru/faq/_includes/common.md -->
<!-- endsource: ru/faq/common.md -->


## SDK {#SDK}

<!-- source: ru/faq/sdk.md -->
<!-- source: ru/faq/_includes/sdk.md -->
# SDK

## Что делать, если SDK экстренно завершает работу при завершении работы приложения? {#what-to-do-if-the-sdk-crashes-urgently-when-the-app-is-shut-down}

Не следует оборачивать компоненты SDK в синглтон, так как время их жизни не должно превышать время выполнения функции `main()`. Так как при уничтожении клиента происходит опустошение пулов сессий, требуется возможность перехода по сети. Но gPRC содержит глобальные статические переменные, которые к этому времени уже могут быть разрушены. Таким образом, работа gRPC невозможна. При необходимости сделать драйвер глобальным объектом, на драйвере нужно вызвать функцию `Stop(true)` перед выходом из `main()`.

## Что делать, если при вызове `fork()` в дочернем процессе программа работает некорректно? {#program-does-not-work-correctly-when-calling-fork}

Вызов `fork()` в многопоточных приложениях является антипаттерном. Так как и SDK, и gRPC-библиотека являются многопоточными приложениями, стабильность их работы не гарантируется.

## Что делать, если я получаю ошибку «Active sessions limit exceeded», хотя текущее количество активных сессий не превышает лимит? {#active-sessions-does-not-exceed-the-limit}

Лимит действует на количество активных сессий. Активная сессия — сессия, переданная клиенту для использования в его коде. Сессия возвращается в пул в деструкторе. При этом, сама сессия является копируемым объектом. Возможно, вы сохранили в коде копию сессии.

## Есть ли возможность делать запросы к разным БД из одного приложения? {#make-requests-to-different-databases-from-the-same-application}

Да, C++ SDK позволяет переопределять параметры БД и токен в момент создания клиента. Отдельные драйверы создавать не нужно.

## Что делать, если отказала одна из ВМ и невозможно сделать запрос? {#vms-failed-and-you-cant-make-a-request}

Чтобы выявить недоступность ВМ, нужно проставить клиентский таймаут. Все запросы содержат параметры для клиентского таймаута. Величина таймаута должна быть на порядок больше ожидаемого времени выполнения запроса.
<!-- endsource: ru/faq/_includes/sdk.md -->
<!-- endsource: ru/faq/sdk.md -->


## Ошибки {#errors}

<!-- source: ru/faq/errors.md -->
<!-- source: ru/faq/_includes/errors.md -->
# Ошибки

## Почему может возникать ошибка «Status: OVERLOADED Error: Pending previous query completion» в C++ SDK?

Q: При запуске двух запросов, пытаюсь получить ответ из фьючера от второго из них. Получаю: `Status: OVERLOADED Why: <main>: Error: Pending previous query completion`.

A: Сессия в SDK однопоточная. Если нужно параллельно использовать несколько запросов, нужно создавать несколько сессий.

## Что делать, если я часто получаю ошибку «Transaction locks invalidated»? {#locks-invalidated}

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

## Почему возникает ошибка «Exceeded maximum allowed number of active transactions»? {#exceed-number-transactions}

В логике на клиентской стороне надо стараться держать как можно более короткие транзакции.

В рамках сессии разрешено не более 10 активных транзакций. При старте транзакции нужно использовать либо коммит-флаг для автокоммита, либо явный коммит/роллбек.

## Что делать, если при запросе я получаю ошибку «Datashard: Reply size limit exceeded»? {#reply-size-exceeded}

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

Рекомендации:

* Общая рекомендация — уменьшить объем данных, обрабатываемых в транзакции.
* Если выполняется операция `Join`, стоит убедиться, что она выполняется способом [Index lookup Join](https://ydb.tech/docs/ru/faq/yql.md#index-lookup-join).
* Если осуществляется простая выборка, стоит убедиться, что она делается по ключам, или добавить `LIMIT` в запрос.

## Что делать, если при запросе я получаю ошибку «Datashard program size limit exceeded»? {#program-size-exceeded}

Данная ошибка означает, что размер программы (в сумме со значениями параметров) для одного из даташардов превысил лимит в 50 МБ. Чаще всего это означает попытку записать в таблицы базы более 50 МБ данных в одной транзакции. В качестве записей учитываются все модифицирующие операции в транзакции, такие как `UPSERT`, `REPLACE`, `INSERT`, `UPDATE`.

Необходимо уменьшить суммарных объем записей в одной транзакции. В общем случае не рекомендуется объединять в единую транзакцию запросы, которые логически не требуют транзакционности. В случае добавления/обновления данных батчами, рекомендуется уменьшить размер одного батча до значений, не превышающих нескольких мегабайт.
<!-- endsource: ru/faq/_includes/errors.md -->
<!-- endsource: ru/faq/errors.md -->

## YQL {#yql}

<!-- source: ru/faq/yql.md -->
<!-- source: ru/faq/_includes/yql.md -->
# YQL

## Общие вопросы {#common}

### Как выбрать из таблицы строчки по заданному списку ключей? {#explicit-keys}

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

```yql
DECLARE $keys AS List<UInt64>;

SELECT * FROM some_table
WHERE Key1 IN $keys;
```

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

```yql
DECLARE $keys AS List<Tuple<UInt64, String>>;

SELECT * FROM some_table
WHERE (Key1, Key2) IN $keys;
```

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

### Осуществляется ли поиск по индексу для условий, содержащих оператор LIKE? {#like-index}

Оператор `LIKE` может быть использован для поиска по индексу таблицы только в случае, если он задает префикс строки:

```yql
SELECT * FROM string_key_table
WHERE Key LIKE "some_prefix%";
```

### Почему в результате запроса выводится только 1000 строк? {#result-rows-limit}

1000 строк — ограничение на размер одного результата для YQL запроса. В случае если результат запроса был обрезан, он будет помечен флагом `Truncated`. Чтобы получить большее количество строк из таблицы, можно воспользоваться [постраничным выводом](https://ydb.tech/docs/ru/dev/paging.md) или операцией `ReadTable`.

### Как экранировать кавычки JSON-строк при добавлении их в таблицу? {#escaping-quotes}

Рассмотрим пример c двумя возможными вариантами добавления JSON-строки в таблицу:

```yql
UPSERT INTO test_json(id, json_string)
VALUES
    (1, Json(@@[{"name":"Peter \"strong cat\" Kourbatov"}]@@)),
    (2, Json('[{"name":"Peter \\\"strong cat\\\" Kourbatov"}]'))
;
```

Для вставки значения в первой строке используется `raw string` и способ экранирования с помощью `\"`. Для вставки второй строки используется экранирование через `\\\"`.

Мы рекомендуем применять `raw string` и способ экранирования с помощью `\"`, так как он более нагляден.

### Как обновить только те значения, ключей которых нет в таблице? {#update-non-existent}

Можно использовать операцию `LEFT JOIN`, чтобы пометить отсутствующие в таблице ключи, после чего обновить их значения:

```yql
DECLARE $values AS List<Struct<Key: UInt64, Value: String>>;

UPSERT INTO kv_table
SELECT v.Key AS Key, v.Value AS Value
FROM AS_TABLE($values) AS v
LEFT JOIN kv_table AS t
ON v.Key = t.Key
WHERE t.Key IS NULL;
```

## Операции Join {#joins}

### Есть ли особенности в работе операции Join? {#join-operations}

Операция `Join` в YDB выполняется одним из двух способов:

* Common Join;
* Index Lookup Join.

### Common Join {#common-join}

Содержимое обеих таблиц (левая и правая части `Join`) отправляется на выполняющий запрос узел, где операция выполняется над данными целиком. Это универсальный способ выполнения операции `Join`, который применяется в случае, когда более оптимальные способы неприменимы. Для больших таблиц такой способ или работает медленно, или в общем случае не работает из-за превышения лимитов на пересылку данных.

### Index lookup Join {#index-lookup-join}

Для строчек из левой части операции `Join` осуществляется поиск (lookup) соответствующих значений в правой части. Данный способ применяется, когда правая часть является таблицей и ключ операции `Join` является префиксом ее первичного ключа или ключа вторичного индекса. При использовании данного способа из правой таблицы делаются ограниченные выборки, вместо полного чтения, что позволяет использовать его при работе с большими таблицами.

{% note info %}

Для большинства OLTP запросов рекомендуется использовать Index Lookup Join с небольшим размером левой части. Такие операции читают мало данных и могут быть выполнены эффективно.

{% endnote %}

### Как сделать Join с данными из параметров запроса? {#constant-table-join}

Данные из параметров запроса можно использовать как константную таблицу. Для этого нужно использовать модификатор `AS_TABLE` с параметром, имеющим тип списка структур:

```yql
DECLARE $data AS List<Struct<Key1: UInt64, Key2: String>>;

SELECT * FROM AS_TABLE($data) AS d
INNER JOIN some_table AS t
ON t.Key1 = d.Key1 AND t.Key2 = d.Key2;
```

Явного ограничения на количество записей в константной таблице нет, но нужно иметь в виду стандартное ограничение на общий размер параметров запроса (50 МБ).

### Как лучше реализовать запрос вида (key1, key2) IN ((v1, v2), (v3, v4), ...)? {#key-pairs-in}

Это лучше записывать через JOIN с константной таблицей:

```yql
$keys = AsList(
    AsStruct(1 AS Key1, "One" AS Key2),
    AsStruct(2 AS Key1, "Three" AS Key2),
    AsStruct(4 AS Key1, "One" AS Key2)
);

SELECT t.* FROM AS_TABLE($keys) AS k
INNER JOIN table1 AS t
ON t.Key1 = k.Key1 AND t.Key2 = k.Key2;
```

## Транзакции {#transactions}

### Насколько эффективно выполнение нескольких запросов в транзакции? {#transaction-queries}

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

### Является ли отдельный запрос атомарным? {#atomic-query}

В общем случае YQL-запросы могут выполняться в несколько последовательных фаз. Например, запрос с операцией Join может быть выполнен в две фазы, читающие данные левой и правой таблицы соответственно. Этот аспект является важным при выполнении запроса в транзакции с низким уровнем изоляции (`online_read_only`), так как в этом случае данные между фазами выполнения могут быть изменены другими транзакциями.
<!-- endsource: ru/faq/_includes/yql.md -->
<!-- endsource: ru/faq/yql.md -->

## Аналитика {#analytics}

<!-- source: ru/faq/analytics.md -->
## Можно ли использовать YDB для аналитических нагрузок (OLAP)?

Да, можно. Если это основной тип нагрузки для конкретной таблицы, то убедитесь, что она [колоночная](https://ydb.tech/docs/ru/concepts/datamodel/table.md#column-oriented-tables).

## Как выбирать между строчными и колоночными таблицами?

Аналогично выбору между транзакционными (OLTP) и аналитическими (OLAP) системами управления базами данных, этот вопрос сводится к ряду компромиссов, которые необходимо учитывать:

* **Каков основной сценарий использования таблицы?** Для преимущественно транзакционных (OLTP) нагрузок используйте [строчные таблицы](https://ydb.tech/docs/ru/concepts/datamodel/table.md#row-oriented-tables). Для аналитических нагрузок (OLAP) используйте [колоночные таблицы](https://ydb.tech/docs/ru/concepts/datamodel/table.md#column-oriented-tables). Транзакционные нагрузки характеризуются высокой частотой запросов, каждый из которых затрагивает небольшое количество строк. Аналитические нагрузки связаны с обработкой больших объёмов данных для получения относительно небольших результатов запросов.
* **Как модифицируется таблица?** Как правило, строчные таблицы лучше работают, когда данные часто изменяются на месте, тогда как колоночные таблицы лучше подходят, когда данные в основном добавляются в виде новых строк. Таким образом, строчные таблицы обычно отражают текущее состояние набора данных, тогда как колоночные часто хранят историю каких-то неизменяемых событий.
* **Какие функциональные возможности нужны?** Хоть YDB и стремится к функциональному паритету между строчными и колоночными таблицами, могут быть текущие ограничения, которые следует учитывать. Для получения подробностей ознакомьтесь с документацией о конкретной функциональности, которую планируется использовать с данной таблицей.

В отличие от большинства других систем управления базами данных, YDB поддерживает как строчные, так и колоночные таблицы в одной и той же [базе данных](https://ydb.tech/docs/ru/concepts/glossary.md#database). Однако имейте в виду, что транзакционные и аналитические нагрузки имеют разные паттерны потребления ресурсов и могут влиять друг на друга при перегруженном кластере.
<!-- endsource: ru/faq/analytics.md -->

## Известные проблемы {#known-issues}

<!-- source: ru/faq/known-issues.md -->
<!-- source: ru/faq/_includes/known-issues.md -->
# Известные проблемы

## Не происходит объединение партиций таблицы при включённом автопартицировании {#table-partitions-are-not-merging}

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

Проблема специфична для таблиц, соответствующих двум следующим критериям:

* Таблица была создана на кластере YDB до версии 22.2.
* На момент создания таблицы или впоследствии для неё не было задано значение минимального количества партиций.

Для устранения проблемы нужно явно задать для таблицы значение минимального количества партиций, например, с помощью параметра [AUTO_PARTITIONING_MIN_PARTITIONS_COUNT](https://ydb.tech/docs/ru/concepts/datamodel/table.md#auto_partitioning_min_partitions_count):

```yql
ALTER TABLE `my_table` SET (AUTO_PARTITIONING_MIN_PARTITIONS_COUNT = 1);
```
<!-- endsource: ru/faq/_includes/known-issues.md -->
<!-- endsource: ru/faq/known-issues.md -->
<!-- endsource: ru/faq/_includes/all.md -->

