Skip to content

Commit

Permalink
Ru documentation for automatic secondary indices usage (#3131)
Browse files Browse the repository at this point in the history
Co-authored-by: Ivan Blinkov <ivan@ydb.tech>
  • Loading branch information
ssmike and blinkov authored Sep 20, 2024
1 parent d73903d commit 41236b0
Showing 1 changed file with 79 additions and 0 deletions.
79 changes: 79 additions & 0 deletions ydb/docs/ru/core/dev/secondary-indexes.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,85 @@ WHERE o.id_customer = $customer_id

В транзакционных приложениях подобные информационные запросы выполняются с использованием поcтраничного вывода данных, что исключает рост стоимости и времени исполнения при увеличении количества записей, подходящих под условия фильтрации. Описанный на примере первичного ключа подход к написанию [постраничных запросов](../dev/paging.md) применим также и к колонкам, включенным во вторичный индекс.

Также реализована экспериментальная возможность выбора вторичного индекса для использования в запросе в автоматическом режиме. Алгоритм выбора на данный момент является rule-based и использует только текст запроса для автоматического выбора вторичного индекса.

### Автоматическое использование индексов при выборке

{% note warning %}

Данный механизм является экспериментальным и по умолчанию пока выключен. Его включение производится с помощью [настройки `index_auto_choose_mode` в `table_service_config`](https://github.com/ydb-platform/ydb/blob/main/ydb/core/protos/table_service_config.proto#L268). Настройка также будет влиять на поведение query service.

{% endnote %}

Явное указание секции `VIEW` имеет приоритет над решением оптимизатора о использовании вторичных индексов. То есть запрос

```yql
SELECT * FROM `Table` VIEW Index
```

гарантированно будет производить выборку с использованием индекса `Index`.

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

```yql
SELECT * FROM `Table` VIEW PRIMARY KEY
```

#### Критерии выбора вторичного индекса

Выбор индекса используемого для чтения происходит во время оптимизации запроса при определении диапазонов строк, которые необходимо прочитать (predicate pushdown). Индексы, как и основная таблица представляют из себя набор строк упорядоченных по набору ключевых колонок.

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

1. Необходимость дополнительного чтения из основной таблицы. Если в индексе присутствуют все нужные для запроса колонки, то дополнительные чтения не требуются.
2. Длина точечного префикса предиката для ключа соответствующей таблицы. То есть, предикат ограничивает некоторый набор колонок являющихся первыми компонентами ключа точечными условиями: `=`, `IN`, `IS NULL`. Здесь приоритет отдается индексам, для которых зафиксированы все индексируемые колонки или основной таблице если точечным является первичный ключ целиком.
3. Количество использованных колонок в границах диапазона для чтения. В следующем запросе к таблице Table с первичным ключом (Key1, Key2, Key3)

```yql
SELECT * FROM `Table` WHERE (Key1, Key2, Key3) < ($param1, $param2, $param3) AND (Key1, Key2) > ($param4, $param5)
```

чтение будет производиться в диапазоне `(($param4, $param5), ($param1, $param2, $param3))` и таким образом количество использованных колонок будет равно 3. Аналогично 2 здесь отдается предпочтение индексам для которых использованы все индексируемые колонки.

Способы чтения ранжируются между собой в соответствии с критерием 2, при равенстве с критерием 3 и дополнительно учитывается критерий 1.

#### Примеры автоматического выбора индексов

```yql
CREATE TABLE `Table` (
Key Int32,
SubKey1 Int32,
SubKey2 String,
Value1 String,
Value2 String,
PRIMARY KEY (Key, SubKey1, SubKey2),
INDEX Index12 GLOBAL ON (SubKey1, SubKey2),
INDEX Index21 GLOBAL ON (SubKey2, Value1),
INDEX Index212 GLOBAL ON (SubKey2) COVER (Value2)
);
```

`SELECT * FROM Table WHERE SubKey1 = $p1 and SubKey2 > $p2`— будет использован `Index12`. Выражение для диапазона — `(($p1; $p2), ($p1)]`. Длина точечного префикса для `Index12` — 1, для остальных индексов — 0.

`SELECT * FROM Table WHERE Key = $p1 and SubKey1 = $p2 And SubKey2 = $p2` — индекс не будет использоваться. При выборе скана основной таблицы используется все 3 колонки `[Key, Fk1, Fk2]`, длина точечного префикса 3.`

`SELECT * FROM Table WHERE Key = $p1 and SubKey2 = $p2` — вторичные индексы не будут использоваться. При выборе любого вторичного индекса используется 1 колонка, точечный префикс также не более 1 при любом варианте выбора индекса.

`SELECT * FROM Table WHERE Key >= $p1 and SubKey1 = $p2 And SubKey2 = $p3` — должен быть выбран Index12, так как при его выборе в получающемся диапазоне `[[Fk1; Fk2; Key], [Fk1; Fk2])` получится длина точечного префикса — 2, и будут использоваться 3 колонки.

`SELECT * FROM Table WHERE Key = 2 and SubKey2 = 3` — вторичные индексы не должны быть использованы. В случае чтения по `PK` и при использовании любого из вторичных индексов точечный префикс состоит не более чем из одной колонки. Также используется не более одной колонки.

`SELECT * FROM Table WHERE SubKey1 > 2` — Должен быть выбран `Index12`. Только при использовании `Index12` будет нетривиальный диапазон для чтения.

`SELECT * FROM Table WHERE SubKey2 = 2` — Может быть выбран любой из `Index21` и `Index212`. При использовании вышеупомянутых индексов длина точечного префикса будет 1. Количество использованных колонок также максимизируется при выборе `Index21` и `Index212`

`SELECT Value2 FROM Table WHERE SubKey2 = 2` — Должен быть выбран Index212. При использовании Index21 и Index212 длина точечного префикса будет 1, но при использовании Index212 не нужно чтение основной таблицы.

`SELECT * FROM Table WHERE SubKey2 > 2` — Будут использованы `Index21` или `Index212`, так как читаемый диапазон нетривиален только при их использовании.

`SELECT * FROM Table WHERE SubKey1 = 2` — Будет использован `Index12`, так как при его использовании длина точечного префикса будет 1, а в остальных случаях 0.

## Проверка стоимости запроса {#cost}

Любой запрос в транзакционном приложении необходимо проверять с точки зрения того, сколько он выполнил операций ввода-вывода в базе данных и сколько CPU было потрачено на его исполнение. Также необходимо убедиться, что эти цифры не растут бесконечно с ростом объема базы данных. В {{ ydb-short-name }} после выполнения каждого запроса возвращается статистика, содержащая необходимую для анализа информацию.
Expand Down

0 comments on commit 41236b0

Please sign in to comment.