From 3b3e5097a89462a682b39294f94e2f252f4da7f7 Mon Sep 17 00:00:00 2001
From: "a.tolstoy" <a.tolstoy@picodata.io>
Date: Wed, 10 Apr 2024 14:29:43 +0300
Subject: [PATCH] introduce join.md

---
 docs/images/inner_join.svg     | Bin 0 -> 9156 bytes
 docs/images/left_join.svg      | Bin 0 -> 9158 bytes
 docs/images/multiple_joins.svg | Bin 0 -> 20325 bytes
 docs/reference/sql/join.md     | 365 +++++++++++++++++++++++++++++++++
 docs/reference/sql/select.md   |   6 +-
 docs/sql_index.md              |   4 +
 mkdocs.yml                     |   2 +
 7 files changed, 376 insertions(+), 1 deletion(-)
 create mode 100644 docs/images/inner_join.svg
 create mode 100644 docs/images/left_join.svg
 create mode 100644 docs/images/multiple_joins.svg
 create mode 100644 docs/reference/sql/join.md

diff --git a/docs/images/inner_join.svg b/docs/images/inner_join.svg
new file mode 100644
index 0000000000000000000000000000000000000000..ae7d82c70accf88f620753d9a0a99aea774850ae
GIT binary patch
literal 9156
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
F{TI`~&m8~&

literal 0
HcmV?d00001

diff --git a/docs/images/left_join.svg b/docs/images/left_join.svg
new file mode 100644
index 0000000000000000000000000000000000000000..70bfd86ea0009463f718d47ba2a329a738c9933a
GIT binary patch
literal 9158
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

literal 0
HcmV?d00001

diff --git a/docs/images/multiple_joins.svg b/docs/images/multiple_joins.svg
new file mode 100644
index 0000000000000000000000000000000000000000..7ab69ff82dc50e461cf14e002496b18238785985
GIT binary patch
literal 20325
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
L*ZhNPKfL%qyZ<){

literal 0
HcmV?d00001

diff --git a/docs/reference/sql/join.md b/docs/reference/sql/join.md
new file mode 100644
index 00000000..d8c4d85a
--- /dev/null
+++ b/docs/reference/sql/join.md
@@ -0,0 +1,365 @@
+# Использование JOIN {: #join }
+
+JOIN представляет собой параметр, используемый при SELECT-запросах с
+целью получения данных из двух или более таблиц. Данный параметр
+позволяет соединять колонки таблиц по заданному условию (оператор `ON`)
+и тем самым создавать новую результирующую таблицу из указанных столбцов
+изначальных таблиц. Соединение таблиц производится с использованием
+перекрестного (декартова) произведения их кортежей (строк).
+
+См. также:
+
+- [SELECT](select.md)
+
+## Расположение таблиц {: #join_tables }
+
+Запрос с соединением всегда подразумевает наличие _внешней_ таблицы, а
+также одной или нескольких _внутренних_ таблиц. Внешняя таблица
+находится слева от параметра `JOIN`, а внутренние — справа.
+
+Соединение таблиц всегда производится последовательно, в порядке,
+указанном в запросе:
+
+```sql
+"table1" JOIN "table2" JOIN "table3" -> ("table1" JOIN "table2") JOIN "table3"
+```
+
+## Типы соединения {: #join_types }
+
+Picodata поддерживает два типа соединения: `INNER JOIN` и `LEFT JOIN`.
+
+### INNER JOIN {: #inner_join }
+
+`INNER JOIN` — внутреннее соединение. Используется по умолчанию в тех
+случаях, когда в запросе указан параметр `JOIN` без уточнения.
+
+<div align="center">
+![INNER JOIN](../../images/inner_join.svg)
+</div>
+
+Данный тип означает, что к колонкам каждого кортежа из внутренней
+(правой) части запроса присоединяются только колонки тех кортежей
+внешней (левой) части, которые удовлетворяют условию соединения `ON`.
+Если во внешней части не нашлось подходящего кортежа, то внутренний
+кортеж не попадает в результат.
+
+### LEFT JOIN {: #left_join }
+
+`LEFT JOIN ` / `LEFT OUTER JOIN `— внешнее левое соединение.
+
+<div align="center">
+![LEFT JOIN](../../images/left_join.svg)
+</div>
+
+Данный тип означает, что к колонкам каждого кортежа из внешней (левой)
+части запроса присоединяются только колонки тех кортежей внутренней
+(правой) части, которые удовлетворяют условию соединения `ON`. Если во
+внутренней части не нашлось подходящего кортежа, то вместо значений
+его колонок будет подставлен `NULL`.
+
+## Условия соединения {: #join_condition }
+
+Условие соединения позволяет сопоставить строки разных таблиц и является
+обязательным для запросов со любым типом JOIN. Условие следует после
+ключевого слова `ON` и, в большинстве случаев, соответствует одному из
+следующих типов:
+
+- равенство колонок (`characters.id = assets.id`)
+- математическое выражение (`characters.id > 2`)
+- литерал (`TRUE` / `FALSE`)
+
+Любое соединение с JOIN является декартовым произведением кортежей из
+внешней и внутренней таблицы с фильтрацией по условию соединения.
+Поэтому результирующая таблица может быть как максимально возможного
+размера (например, при условии `ON TRUE` будут взаимно перемножены _все_
+кортежи), так и некоторого меньшего размера, в зависимости от заданного
+условия.
+
+См. также:
+
+- [Выражение (expression)](select.md#expression)
+
+## Примеры запросов {: #join_examples }
+
+Разница между левым и внутренним соединением проявляется в случаях,
+когда для части кортежей внешней таблицы отсутствуют подходящие под
+условие соединения кортежи из внутренней таблицы. При внутреннем
+соединении они будут отфильтрованы, при левом внешнем — оставлены, но на
+месте отсутствующих значений будет `nil`.
+
+Покажем это на примере соединения по равенству колонок для таблиц
+`characters` и `assets`:
+
+<details><summary>Содержимое таблиц</summary><p>
+
+```sql
+picodata> select * from "characters"
++----+-------------------+------+
+| id | name              | year |
++===============================+
+| 1  | "Woody"           | 1995 |
+|----+-------------------+------|
+| 2  | "Buzz Lightyear"  | 1995 |
+|----+-------------------+------|
+| 3  | "Bo Peep"         | 1995 |
+|----+-------------------+------|
+| 4  | "Mr. Potato Head" | 1995 |
+|----+-------------------+------|
+| 5  | "Woody"           | 1995 |
+|----+-------------------+------|
+| 10 | "Duke Caboom"     | 2019 |
++----+-------------------+------+
+(6 rows)
+picodata> select * from "assets"
++----+------------------+-------+
+| id | name             | stock |
++===============================+
+| 1  | "Woody"          | 2561  |
+|----+------------------+-------|
+| 2  | "Buzz Lightyear" | 4781  |
++----+------------------+-------+
+(2 rows)
+```
+</p></details>
+
+Пример левого соединения:
+
+```sql
+SELECT "characters"."name", "characters"."year", "assets"."stock"
+FROM "characters"
+LEFT JOIN "assets"
+ON "characters"."id" = "assets"."id"
+```
+
+Результат:
+
+```shell
++-------------------+-----------------+--------------+
+| characters.name   | characters.year | assets.stock |
++====================================================+
+| "Woody"           | 1995            | 2561         |
+|-------------------+-----------------+--------------|
+| "Buzz Lightyear"  | 1995            | 4781         |
+|-------------------+-----------------+--------------|
+| "Bo Peep"         | 1995            | nil          |
+|-------------------+-----------------+--------------|
+| "Mr. Potato Head" | 1995            | nil          |
+|-------------------+-----------------+--------------|
+| "Woody"           | 1995            | nil          |
+|-------------------+-----------------+--------------|
+| "Duke Caboom"     | 2019            | nil          |
++-------------------+-----------------+--------------+
+(6 rows)
+```
+
+Пример внутреннего соединения:
+
+```sql
+SELECT "characters"."name", "characters"."year", "assets"."stock"
+FROM "characters"
+INNER JOIN "assets"
+ON "characters"."id" = "assets"."id"
+```
+
+Результат:
+
+```shell
++------------------+-----------------+--------------+
+| characters.name  | characters.year | assets.stock |
++===================================================+
+| "Woody"          | 1995            | 2561         |
+|------------------+-----------------+--------------|
+| "Buzz Lightyear" | 1995            | 4781         |
++------------------+-----------------+--------------+
+(2 rows)
+```
+
+## Множественные соединения {: #multiple_joins }
+
+Соединять можно не только две, но и большее число таблиц. В запросе с
+несколькими соединениями могут быть использованы разные комбинации
+левого и внутреннего соединения.
+
+Для примера с двумя соединениями задействуем третью тестовую таблицу.
+
+<details><summary>Содержимое таблицы</summary><p>
+
+```sql
+picodata> select * from "cast"
++------------------+---------------+-------------+
+| character        | actor         | film        |
++================================================+
+| "Bo Peep"        | "Annie Potts" | "Toy Story" |
+|------------------+---------------+-------------|
+| "Buzz Lightyear" | "Tim Allen"   | "Toy Story" |
+|------------------+---------------+-------------|
+| "Woody"          | "Tom Hanks"   | "Toy Story" |
++------------------+---------------+-------------+
+(3 rows)
+```
+</details>
+
+Сделаем соединение трех таблиц с тем, чтобы узнать актеров всех
+персонажей из `characters` независимо от того, есть ли для
+соответствующих игрушек данные об остатках на складе.
+
+<p align="center">
+![MULTIPLE JOINS](../../images/multiple_joins.svg)
+</p>
+
+Запрос:
+
+```sql
+SELECT "characters"."name", "assets"."stock", "cast"."actor"
+FROM "characters"
+LEFT JOIN "assets"
+ON "characters"."id" = "assets"."id"
+JOIN "cast"
+ON "characters"."name" = "cast"."character"
+```
+
+Результат:
+
+```shell
++------------------+--------------+---------------+
+| characters.name  | assets.stock | cast.actor    |
++=================================================+
+| "Woody"          | 2561         | "Tom Hanks"   |
+|------------------+--------------+---------------|
+| "Buzz Lightyear" | 4781         | "Tim Allen"   |
+|------------------+--------------+---------------|
+| "Bo Peep"        | nil          | "Annie Potts" |
+|------------------+--------------+---------------|
+| "Woody"          | nil          | "Tom Hanks"   |
++------------------+--------------+---------------+
+(4 rows)
+```
+
+## Перемещение данных {: #join_motions }
+
+При выполнении распределенного запроса, соединение таблиц может
+сопровождаться полным или частичным перемещением данных, либо не
+требовать перемещения данных совсем. Критерием здесь выступает условие
+соединения (`ON`).
+
+При необходимости перемещения данных, в план выполнения запроса перед
+сканированием внутренней таблицы добавляется motion-узел, который
+обеспечивает перекачку недостающих данных на бакеты, содержащие данные
+внешней таблицы.
+
+См. также:
+
+- [EXPLAIN и варианты перемещения данных](explain.md#data_motion_types)
+
+### Отсутствие перемещения {: #no_motion }
+
+Перемещение данных не происходит, если в условии соединения использовано
+равенство колонок, которые входят в ключи распределения соответствующих
+таблиц.
+
+К примеру, в условии соединения указано `ON "characters"."id" =
+"assets"."id"`, и таблицы "characters" и "assets" обе распределены по
+своим колонкам "id":
+
+```sql
+picodata> EXPLAIN SELECT "characters"."name", "characters"."year", "assets"."stock"
+FROM "characters"
+LEFT JOIN "assets"
+ON "characters"."id" = "assets"."id"
+projection ("characters"."name"::string -> "name", "characters"."year"::integer -> "year", "assets"."stock"::integer -> "stock")
+    left join on ROW("characters"."id"::integer) = ROW("assets"."id"::integer)
+        scan "characters"
+            projection ("characters"."id"::integer -> "id", "characters"."name"::string -> "name", "characters"."year"::integer -> "year")
+                scan "characters"
+        scan "assets"
+            projection ("assets"."id"::integer -> "id", "assets"."name"::string -> "name", "assets"."stock"::integer -> "stock")
+                scan "assets"
+```
+
+### Частичное перемещение {: #segment_motion }
+
+Частичное перемещение означает, что недостающая часть внутренней таблицы
+должна быть скопирована на узлы, содержащие данные внешней таблицы.
+
+К примеру, в условии соединения указано `ON "characters"."id" =
+"assets"."id"`, но таблица "characters" распределена по колонке "id", а
+"assets" — по какой-то другой колонке:
+
+```sql
+picodata> EXPLAIN SELECT "characters"."name", "characters"."year", "assets"."stock"
+FROM "characters"
+LEFT JOIN "assets"
+ON "characters"."id" = "assets"."id"
+projection ("characters"."name"::string -> "name", "characters"."year"::integer -> "year", "assets2"."stock"::integer -> "stock")
+    left join on ROW("characters"."id"::integer) = ROW("assets"."id"::integer)
+        scan "characters"
+            projection ("characters"."id"::integer -> "id", "characters"."name"::string -> "name", "characters"."year"::integer -> "year")
+                scan "characters"
+        motion [policy: segment([ref("id")])]
+            scan "assets"
+                projection ("assets"."id"::integer -> "id", "assets"."name"::string -> "name", "assets"."stock"::integer -> "stock")
+                    scan "assets"
+```
+
+### Полное перемещение {: #full_motion }
+
+Полное перемещение означает, что вся внутренняя таблица
+должна быть скопирована на узлы, содержащие данные внешней таблицы.
+
+Такая ситуация возникает, если в условии соединения указана колонка
+внешней таблицы, не входящая в ее ключ распределения.
+
+К примеру, в условии соединения указано `ON "characters"."id" =
+"assets"."id"`, но таблица "characters" распределена по какой-то другой
+колонке, в то время как "assets" распределена по "id":
+
+```sql
+picodata> EXPLAIN SELECT "characters"."name", "characters"."year", "assets"."stock"
+FROM "characters"
+LEFT JOIN "assets"
+ON "characters"."id" = "assets"."id"
+projection ("characters"."name"::string -> "name", "characters"."year"::integer -> "year", "assets"."stock"::integer -> "stock")
+    left join on ROW("characters"."id"::integer) = ROW("assets"."id"::integer)
+        scan "characters"
+            projection ("characters"."id"::integer -> "id", "characters"."name"::string -> "name", "characters"."year"::integer -> "year")
+                scan "characters"
+        motion [policy: full]
+            scan "assets"
+                projection ("assets"."id"::integer -> "id", "assets"."name"::string -> "name", "assets"."stock"::integer -> "stock")
+                    scan "assets"
+```
+
+Также, при использовании математических выражений или литералов, перемещение всегда будет полным:
+
+```sql
+picodata> EXPLAIN SELECT "characters"."name", "characters"."year", "assets"."stock"
+FROM "characters"
+LEFT JOIN "assets"
+ON "characters"."id" = 1
+projection ("characters"."name"::string -> "name", "characters"."year"::integer -> "year", "assets"."stock"::integer -> "stock")
+    left join on ROW("characters"."id"::integer) = ROW(1::unsigned)
+        scan "characters"
+            projection ("characters"."id"::integer -> "id", "characters"."name"::string -> "name", "characters"."year"::integer -> "year")
+                scan "characters"
+        motion [policy: full]
+            scan "assets"
+                projection ("assets"."id"::integer -> "id", "assets"."name"::string -> "name", "assets"."stock"::integer -> "stock")
+                    scan "assets"
+```
+
+```sql
+picodata> EXPLAIN SELECT "characters"."name", "characters"."year", "assets"."stock"
+FROM "characters"
+LEFT JOIN "assets"
+ON TRUE
+projection ("characters"."name"::string -> "name", "characters"."year"::integer -> "year", "assets"."stock"::integer -> "stock")
+    left join on true::boolean
+        scan "characters"
+            projection ("characters"."id"::integer -> "id", "characters"."name"::string -> "name", "characters"."year"::integer -> "year")
+                scan "characters"
+        motion [policy: full]
+            scan "assets"
+                projection ("assets"."id"::integer -> "id", "assets"."name"::string -> "name", "assets"."stock"::integer -> "stock")
+                    scan "assets"
+
+```
diff --git a/docs/reference/sql/select.md b/docs/reference/sql/select.md
index 8b32ac76..8fcad789 100644
--- a/docs/reference/sql/select.md
+++ b/docs/reference/sql/select.md
@@ -74,7 +74,11 @@ NOTE: **Примечание** Кортежи в выводе идут в том
   несколько `EXCEPT DISTINCT` подряд. Чтобы обойти это ограничение,
   следует воспользоваться подзапросами.
 
-## Примеры {: #examples }
+См. также:
+
+- [Использование JOIN](join.md)
+
+## Примеры  {: #examples }
 
 Получение данных из таблицы с фильтрацией:
 
diff --git a/docs/sql_index.md b/docs/sql_index.md
index 40041bb2..1c0257a6 100644
--- a/docs/sql_index.md
+++ b/docs/sql_index.md
@@ -32,6 +32,10 @@
 * [UPDATE](reference/sql/update.md)
 * [VALUES](reference/sql/values.md)
 
+## Синтаксис {: #syntax }
+
+* [Использование JOIN](reference/sql/join.md)
+
 ## Функции и операторы {: #functions }
 
 * [Агрегатные функции](reference/sql/aggregate.md)
diff --git a/mkdocs.yml b/mkdocs.yml
index c5da806a..04e4a8da 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -75,6 +75,8 @@ nav:
         - reference/sql/select.md
         - reference/sql/update.md
         - reference/sql/values.md
+      - Синтаксис:
+        - reference/sql/join.md
       - Функции и операторы:
         - reference/sql/aggregate.md
         - reference/sql/cast.md
-- 
GitLab