added Logic_and_Physics_joins
This commit is contained in:
@@ -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. Почему оптимизатор может выбрать разный порядок?
|
||||||
|
потому чтт ему будет так проще соединять таблицы и читать данные
|
||||||
|
|
||||||
Reference in New Issue
Block a user