From 6f96ed5510c95b3f0d22792b02626b81e93651ca Mon Sep 17 00:00:00 2001 From: Dmitry Medvedev Date: Sat, 4 Jul 2026 13:47:18 +0500 Subject: [PATCH] added Logic_and_Physics_joins --- dmedvedev/10.6.Logic_and_Physics_joins.sql | 192 +++++++++++++++++++++ 1 file changed, 192 insertions(+) create mode 100644 dmedvedev/10.6.Logic_and_Physics_joins.sql diff --git a/dmedvedev/10.6.Logic_and_Physics_joins.sql b/dmedvedev/10.6.Logic_and_Physics_joins.sql new file mode 100644 index 0000000..fe6faa4 --- /dev/null +++ b/dmedvedev/10.6.Logic_and_Physics_joins.sql @@ -0,0 +1,192 @@ +- **Задача 1** — Когда какой метод? + + ✅ Заполни таблицу: + + | **Ситуация** | **Какой JOIN выберет база?** | **Почему?** | + | --- | --- | --- | + | 10 пользователей, 1 млн заказов, есть индекс на orders.user_id | Nested Loop | Потому что есть индекс по одному полю и одна таблица мееьше другой сильно | + | 100 000 пользователей, 100 000 заказов, нет индексов | Hash Join | Нет ни индексов, ни сортировки | + | Обе таблицы отсортированы по ключу, есть индексы | Merge Join | Потому что есть и индексы и сортировка | + | Маленькая таблица (5 строк) соединяется с большой (1 млн строк), нет индекса | Hash Join | Потому что нет индекса | + + +- **Задача 2** — Размер таблиц имеет значение + + ✅ Создай тестовые данные: + + + -- Маленькая таблица (10 строк) + CREATE TABLE small_users AS + SELECT generate_series(1, 10) AS id, 'User ' || generate_series(1, 10) AS name; + + -- Большая таблица (100 000 строк) + CREATE TABLE big_orders AS + SELECT + generate_series(1, 100000) AS id, + (random() * 9 + 1)::int AS user_id, + CURRENT_DATE - (random() * 365)::int AS order_date; + + + ✅ Теперь выполни: + + + -- Вариант 1: Без индекса + EXPLAIN ANALYZE + SELECT u.name, COUNT(o.id) + FROM small_users u + JOIN big_orders o ON u.id = o.user_id + GROUP BY u.name; + + -- Вариант 2: С индексом + CREATE INDEX idx_big_orders_user_id ON big_orders(user_id); + + EXPLAIN ANALYZE + SELECT u.name, COUNT(o.id) + FROM small_users u + JOIN big_orders o ON u.id = o.user_id + GROUP BY u.name; + + **❓ Вопросы:** + + 1. Какой метод `JOIN` используется в каждом случае? + В обоих случаях у меня показало Merge Join, просто там где индекс - там Scan Index. + 2. Почему с индексом база может выбрать `Nested Loop`? + Потому что будет маленькая таблица, иногда проще заджойнить большую и маленькую Nested Loop. + 3. Насколько быстрее стало с индексом? + В 2,5 раза. + +- **Задача 3** — Влияние сортировки + + ✅ Выполни три варианта: + + -- Вариант 1: Без ORDER BY + EXPLAIN ANALYZE + SELECT u.name, o.order_date + FROM users u + JOIN orders o ON u.id = o.user_id; + + -- Вариант 2: С ORDER BY по ключу соединения + EXPLAIN ANALYZE + SELECT u.name, o.order_date + FROM users u + JOIN orders o ON u.id = o.user_id + ORDER BY u.id, o.user_id; + + -- Вариант 3: С ORDER BY по другому полю + EXPLAIN ANALYZE + SELECT u.name, o.order_date + FROM users u + JOIN orders o ON u.id = o.user_id + ORDER BY o.order_date; + + **❓Вопросы:** + + 1. Изменился ли тип `JOIN` во втором варианте? + В первом Hash, во втором - Merge. + 2. Появился ли `Merge Join`? + Да. + 3. Почему `ORDER BY` может повлиять на выбор `JOIN`? + Потому что появляется метод при соединении (при условии наличия order by), упрощающий join. + +- **Задача 4** — Найди узкое место + + ✅ Дан медленный запрос: + + SELECT + u.name, + p.name AS product_name, + oi.quantity, + o.order_date + FROM users u + JOIN orders o ON u.id = o.user_id + JOIN order_items oi ON o.id = oi.order_id + JOIN products p ON oi.product_id = p.id + WHERE u.country = 'Россия'; + + **✅ Задание:** + + 1. Выполни с `EXPLAIN ANALYZE` + 2. Посмотри, какие типы `JOIN` используются + Nested Loop and Hash Join. + 3. Есть ли `Seq Scan`? Если да — где? + Да, в трех местах. При чтении таблицы users, orders и products. + 4. Предложи, какие индексы нужно создать + Можно создать 3 индекса + 5. Создай индексы и проверь, изменились ли типы `JOIN` + Изменились, но не сильно, в основном все Hash, один внешний Nested + +- **Задача 5** — Многоступенчатый JOIN + + EXPLAIN ANALYZE + SELECT + u.name, + COUNT(DISTINCT o.id) AS orders_count, + COUNT(DISTINCT oi.product_id) AS products_count + FROM users u + LEFT JOIN orders o ON u.id = o.user_id + LEFT JOIN order_items oi ON o.id = oi.order_id + WHERE u.country = 'Россия' + GROUP BY u.name; + + **✅ Задание:** + + 1. Посмотри на план выполнения + 2. Какие методы `JOIN` используются на каждом уровне? + Hash right join 2 раза + 3. Почему для первого `JOIN` один метод, а для второго — другой? + У меня оба одинаковые, вероятнее всего из-за неверных индексов или чего-то другого. + 4. Сколько строк проходит через каждый `JOIN`? + По одной + +- **Задача 6** — `LEFT JOIN` vs `INNER JOIN` + + ✅ Сравни два запроса: + + -- Вариант A: INNER JOIN + EXPLAIN ANALYZE + SELECT u.name, o.order_date + FROM users u + INNER JOIN orders o ON u.id = o.user_id; + + -- Вариант B: LEFT JOIN + EXPLAIN ANALYZE + SELECT u.name, o.order_date + FROM users u + LEFT JOIN orders o ON u.id = o.user_id; + + **❓ Вопросы:** + + 1. Одинаковый ли тип физического JOIN используется? + Hash and Hash Right + 2. Есть ли разница в Execution Time? + Не сильно , скачет то в одну, то в другую сторону + 3. Почему LEFT JOIN может быть медленнее? + + +- **Задача 7** — Порядок таблиц в JOIN + + ✅ Сравни: + + -- Вариант 1: users JOIN orders + EXPLAIN ANALYZE + SELECT u.name, o.order_date + FROM users u + JOIN orders o ON u.id = o.user_id; + + -- Вариант 2: orders JOIN users + EXPLAIN ANALYZE + SELECT u.name, o.order_date + FROM orders o + JOIN users u ON o.user_id = u.id; + + **❓ Вопросы:** + + 1. Изменился ли тип `JOIN`? + нет + 2. Изменился ли порядок чтения таблиц в плане? + нет + 3. Одинаковое ли `Execution Time`? + Да + 4. Почему оптимизатор может выбрать разный порядок? + потому чтт ему будет так проще соединять таблицы и читать данные +