Browse Source

YDBDOCS-743-optimizer: Optimizer documentation (#8522)

Co-authored-by: Ivan Blinkov <ivan@ydb.tech>
Co-authored-by: Andrey Fomichev <andrey.fomichev@gmail.com>
Pavel Velikhov 6 months ago
parent
commit
656b1b8a22

BIN
ydb/docs/ru/core/concepts/_assets/Star-Schema.png


+ 4 - 0
ydb/docs/ru/core/concepts/glossary.md

@@ -232,6 +232,10 @@
 
 Как и в файловых системах, **папка**, **каталог**, **folder** или **directory** является контейнером для других сущностей. В случае {{ ydb-short-name }}, эти сущности могут быть [таблицами](#table) (включая [внешние таблицы](#external-table)), [топиками](#topic), другими папками и т.д.
 
+### Оптимизатор запросов {#optimizer}
+
+[**Оптимизатор запросов**](https://ru.wikipedia.org/wiki/Оптимизация_запросов_СУБД) — набор компонентов {{ ydb-short-name }}, отвечающих за преобразование логического представления запроса в конкретный физически исполнимый план получения запрошенного результата. Основная цель оптимизатора — выбрать среди всех возможных планов выполнения запроса достаточно эффективный с точки зрения прогнозируемого времени исполнения и потребления ресурсов кластера. Он описан более подробно в отдельной статье [{#T}](optimizer.md).
+
 ## Продвинутая терминология {#advanced-terminology}
 
 Этот раздел объясняет термины, которые полезны для [{{ ydb-short-name }} контрибьюторов](../contributor/index.md) и пользователей, желающих глубже понять, что происходит внутри системы.

+ 81 - 0
ydb/docs/ru/core/concepts/optimizer.md

@@ -0,0 +1,81 @@
+# Оптимзация запросов в {{ ydb-short-name }}
+
+В {{ ydb-short-name }} используются два типа оптимизаторов запросов: оптимизатор, основанный на правилах, и стоимостной оптимизатор. Стоимостной оптимизатор применяется для сложных запросов, как правило, аналитических ([OLAP](https://ru.wikipedia.org/wiki/OLAP)), а оптимизация по правилам работает на всех запросах.
+
+План запроса представляет собой граф операций, таких как чтение данных из источника, фильтрация потока данных по предикату, а также более сложные операции, например [JOIN](../yql/reference/syntax/join.md) и [GROUP BY](../yql/reference/syntax/group_by.md). Оптимизаторы в {{ ydb-short-name }} принимают на вход начальный план запроса и преобразуют его в более эффективный план, эквивалентный начальному с точки зрения возвращаемого результата.
+
+## Оптимизатор запросов основанный на правилах
+
+Значительная часть оптимизаций в {{ ydb-short-name }} применима практически для любых планов запросов, что устраняет необходимость в анализе альтернативных планов и их стоимости. Оптимизатор, основанный на правилах состоит из набора эвристических правил, которые применяются всегда, когда это возможно. Например, практически в любом запросе полезно отфильтровывать неиспользуемые данные как можно раньше в плане исполнения. У каждого правила оптимизатора есть условия срабатывания и логика переписывания плана. Правила применяются итеративно до тех пор, пока существуют правила, применимые к текущему плану.
+
+## Стоимостной оптимизатор запросов
+
+Для более сложных оптимизаций, таких как выбор оптимального порядка джоина и алгоритмов джоинов используется стоимостной оптимизатор. Для каждого запроса стоимостной оптимизатор рассматривает большое количество альтернативных планов выполнения и выбирает из них лучший на основе оценки стоимости каждого варианта. На текущий момент этот оптимизатор работает только с планами, где есть операции [JOIN](../yql/reference/syntax/join.md). Он выбирает наилучший порядок исполнения этих операций, а также выбирает самую эффективную реализацию для каждого Join в плане.
+
+Стоимостной оптимизатор состоит из трех основных компонент:
+
+* Модуль перебора порядка соединений;
+* Модуль оценки стоимости плана;
+* Модуль статистики, на которую опирается оценка стоимости.
+
+### Перебор порядка соединений
+
+Текущий стоимостной оптимизатор в {{ ydb-short-name }} перебирает все полезные варианты соединения таблиц с помощью оператора Join, для которых определены условия соединений. Берется исходный план запроса, из которого строится граф соединений. В зависимости от исходного запроса могут получиться разные топологии этого графа, которые существенно влияют на объем множества альтернативных планов, которое требуется сравнить.
+
+Например, вот типичный пример популярной топологии «звезда», где основная таблица фактов соединяется с многочисленными таблицами измерений:
+
+```sql
+SELECT
+    P.Brand,
+    S.Country AS Countries,
+    SUM(F.Units_Sold)
+
+FROM Fact_Sales F
+INNER JOIN Dim_Date D    ON (F.Date_Id = D.Id)
+INNER JOIN Dim_Store S   ON (F.Store_Id = S.Id)
+INNER JOIN Dim_Product P ON (F.Product_Id = P.Id)
+
+WHERE D.Year = 1997 AND  P.Product_Category = 'tv'
+
+GROUP BY
+    P.Brand,
+    S.Country
+```
+
+В графе этого запроса все таблицы `Dim...` соединяются c таблицей фактов `Fact_Sales`:
+![Граф запроса](_assets/Star-Schema.png)
+
+К типичным топологиям также относятся «цепочка» и «клика». «Цепочка» - это топология, где таблицы соединены друг с другом последовательно и каждая таблица участвует не более, чем в одном соединении. «Клика» — полностью связанный граф, где каждая таблица соединяется с другой.
+
+На практике в OLAP запросах часто встречается топология, представляющая из себя комбинацию «звезы» и «цепочки», сложные топологии вроде «клики» встречаются очень редко.
+
+Топология сильно влияет на количество альтернативных планов, которые требуется рассмотреть оптимизатору. Следовательно, стоимостной оптимизатор ограничивает количество соединений, которые сравниваются полным перебором, в зависимости от топологии исходного плана. Возможности точной оптимизации в {{ ydb-short-name }} приведены в следующей таблице:
+
+| Топология | Кол-во поддерживаемых соединений |
+| --------- | -------------------------------- |
+| Цепочка | 110 |
+| Звезда | 18 |
+| Клика | 15 |
+
+{{ ydb-short-name }} использует модификацию алгоритма [DPHyp](https://www.researchgate.net/publication/47862092_Dynamic_Programming_Strikes_Back) для перебора порядка соединений. Это самый современный алгоритм динамического программирования для оптимизации запросов. Посредством построения гиперграфов запросов он избегает перебора лишних альтернатив и позволяет оптимизировать планы с операторами `JOIN`, сложными предикатами, а также с операторами `GROUP BY` и `ORDER BY`.
+
+### Оценка стоимости планов
+
+Сравнение сложности планов основано на стоимостной функции, которая оценивает ресурсоёмкость каждой операции плана. Основные параметры стоимостной функции — это прогнозы размера входных данных для каждого оператора и размера его результата. Эти прогнозы выполняются на основе статистики, собранной по таблицам {{ ydb-short-name }}, а также анализа самого плана.
+
+### Статистики для стоимостного оптимизатора {#statistics}
+
+Стоимостной оптимизатор использует статистики как по таблице целиком, так и по отдельным колонкам. {{ ydb-short-name }} собирает и поддерживает статистку в актуальном состоянии в фоновом режиме. Форсировать сбор статистики можно с помощью команды [ANALYZE](../yql/reference/syntax/analyze.md).
+
+Текущий набор статистик по таблицам:
+
+* Количество записей таблицы;
+* Размер таблицы в байтах.
+
+Текущий набор статистик по колонкам:
+
+* [Count-min sketch](https://en.wikipedia.org/wiki/Count%E2%80%93min_sketch).
+
+### Текущие уровни стоимостной оптимизации
+
+В {{ ydb-short-name }} можно выставить уровень стоимостной оптимизации через прагму [CostBasedOptimizationLevel](../yql/reference/syntax/pragma.md#costbasedoptimizationlevel)

+ 2 - 0
ydb/docs/ru/core/concepts/toc_i.yaml

@@ -25,3 +25,5 @@ items:
     href: cluster/common_scheme_ydb.md
   - name: Дисковая подсистема кластера
     href: cluster/distributed_storage.md
+- name: Оптимизатор запросов
+  href: optimizer.md

+ 13 - 3
ydb/docs/ru/core/yql/reference/yql-core/syntax/_includes/pragma/ydb.md

@@ -1,7 +1,17 @@
-{% if tech %}
-
 ## YDB
 
+### `ydb.CostBasedOptimizationLevel` {#costbasedoptimizationlevel}
+
+| Уровень | Поведение оптимизатора |
+| ------- | ---------------------- |
+| 0 | Cтоимостный оптимизатор выключен |
+| 1 | Cтоимостный оптимизатор выключен, считаются предсказания оптимизатора |
+| 2 | Cтоимостный оптимизатор включается только для запросов, где участвуют [колоночные таблицы](../../../../../concepts/glossary.md#column-oriented-table) |
+| 3 | Cтоимостный оптимизатор включается для всех запросов, но для строковых таблиц предпочитается алгоритм джоина LookupJoin |
+| 4 | Cтоимостный оптимизатор включен для всех запросов |
+
+{% if tech %}
+
 ### `kikimr.IsolationLevel`
 
 | Тип значения | По умолчанию |
@@ -10,4 +20,4 @@
 
 Экспериментальная pragma, позволяет ослабить уровень изоляции текущей транзакции в YDB.
 
-{% endif %}
+{% endif %}

+ 16 - 0
ydb/docs/ru/core/yql/reference/yql-core/syntax/analyze.md

@@ -0,0 +1,16 @@
+# ANALYZE
+
+`ANALYZE` форсирует сбор табличной и колоночной статитстики для оптимизатора запросов.
+
+Синтаксис:
+
+```yql
+ANALYZE <path_to_table> [ (<column_name> [, ...]) ]
+```
+
+В результате выполнения команды будет собрана и актуализирована статистика по указанной таблицам в целом, а также по всем или указанным колонкам. Комадна ANALYZE синхронная, то есть эта команда завершится только тогда, когда будет собрана и актуализирована указанная статистика.
+
+* `path_to_table` — путь к конкретной таблице, для которой требуется форсированный сбор статистики
+* `column_name` — форсировать сбор статистики только по определённым колонкам таблицы
+
+Текущий набор статистик указан в разделе [{#T}](../../../concepts/optimizer.md#statistics).

+ 4 - 0
ydb/docs/ru/core/yql/reference/yql-core/syntax/pragma.md

@@ -8,6 +8,10 @@
 
 {% include [x](_includes/pragma/files.md) %}
 
+{% if backend_name == "YDB" %}
+
 {% include [x](_includes/pragma/ydb.md) %}
 
+{% endif %}
+
 {% include [x](_includes/pragma/debug.md) %}

+ 1 - 0
ydb/docs/ru/core/yql/reference/yql-core/syntax/toc_i.yaml

@@ -9,6 +9,7 @@ items:
 - { name: ALTER VIEW,                   href: alter-view.md,                 when: feature_view }
 - { name: ALTER TOPIC,                  href: alter-topic.md,                when: feature_topic_control_plane }
 - { name: ALTER USER,                   href: alter-user.md,                 when: feature_user_and_group }
+- { name: ANALYZE,                      href: analyze.md, when: backend_name == "YDB" }
 - { name: CREATE ASYNC REPLICATION,     href: create-async-replication.md,   when: feature_async_replication }
 - { name: CREATE GROUP,                 href: create-group.md,               when: feature_user_and_group }
 - { name: CREATE EXTERNAL DATA SOURCE,  href: create-external-data-source.md,when: feature_federated_queries}