исправлены предыдущие ошибки, добавлен полностью блок по кликхаус и пет-проект

This commit is contained in:
Dmitry Medvedev
2026-09-15 15:34:46 +05:00
parent 297df348c1
commit fb0f37912d
11 changed files with 1235 additions and 2 deletions
+167
View File
@@ -0,0 +1,167 @@
# Задачи на отработку:
### **Задача 1.**
Таблица `products`
| product_id | name |
| --- | --- |
| 101 | iPhone 14 |
| 102 | Galaxy S22 |
| 103 | Pixel 7 |
Таблица `prices`
| product_id | price | region |
| --- | --- | --- |
| 101 | 999 | US |
| 101 | 1049 | EU |
| 102 | 850 | US |
| 102 | 899 | CA |
| 103 | 799 | JP |
1. Сделай `ANY LEFT JOIN`, чтобы получить цену **любой** из регионов.
SELECT
pr.product_id,
p.region,
pr.name,
p.price
FROM prices p
ANY LEFT JOIN products pr ON p.product_id = pr.product_id;
ЗДЕСЬ МЫ ПОЛУЧИМ НА ВЫХОДЕ 5 СТРОК.
А ЕСЛИ БЫ ДЖОЙНИЛИ ТАБЛИЦЫ НАОБОРОТ, ТО ПОЛУЧИЛИ БЫ 3 СТРОКИ.
2. Что будет, если в таблице `prices` несколько цен на один `product_id`?
ВСЕ БУДЕТ ЗАВИСЕТЬ ОТ СОЕДИНЕНИЯ ТАБЛИЦ. ЕСЛИ МЫ ДЖОЙНИМ К ТАБЛИЦЕ С product_id И НА КАЖДОЫЙ ЕСТЬ НЕСКОЛЬКО ЦЕН, ТО В ТАКОМ СЛУЧАЕ КЛИКХАУС ВОЗЬМЕТ ПЕРВОЕ ЗНАЧЕНИЕ С ДИСКА И ПРИСВОИТ ЕГО К product_id, А ОСТАЛЬНЫЕ ЗНАЧЕНИЯ ВЫБРОСИТ.
3. Как повлияет `ALL LEFT JOIN`? Почему в ClickHouse его избегают?
ИЗ-ЗА ПРИМЕНЕНИЯ ОЛЛ ЛЕФТ ДЖОЙН КЛИКХАУС НЕ СМОЖЕТ ВЫБРОСИТЬ НЕНУЖНЫЕ СТРОКИ И УЧТЕТ ВСЕ. В НАШЕМ ПРИМЕРЕ СТРОК СТАНЕТ 5.
ДАННЫЕ МОГУТ ПЕРЕГРУЖАТЬ ПАМЯТЬ И ТОРМОЗИТЬ СИСТЕМУ. МЕТРИКИ МОГУТ СЧИТАТЬСЯ ИСКАЖЕННЫМИ.
### **Задача 2.**
Таблица `ticks`
| time | symbol | price |
| --- | --- | --- |
| 2025-07-17 10:00:00 | AAPL | 190.5 |
| 2025-07-17 10:01:00 | AAPL | 191.2 |
| 2025-07-17 10:02:30 | AAPL | 192.0 |
| 2025-07-17 10:05:00 | GOOG | 2850.0 |
Таблица `orders`
| time | symbol | size |
| --- | --- | --- |
| 2025-07-17 10:00:30 | AAPL | 50 |
| 2025-07-17 10:02:00 | AAPL | 75 |
| 2025-07-17 10:03:00 | AAPL | 20 |
| 2025-07-17 10:04:00 | GOOG | 15 |
1. Сделай `ASOF JOIN`, чтобы каждой сделке найти **предыдущую цену**.
SELECT
o.symbol,
o.size,
t.price,
o.time AS order_time,
t.time AS price_time
FROM orders o
ASOF LEFT JOIN ticks t ON o.symbol = t.symbol AND o.time >= t.time;
2. Почему нельзя использовать обычный `JOIN` по `time = time`?
КАК МИНИМУМ ПОТОМУ ЧТО ВРЕМЯ ПО СДЕЛКЕ И ВРЕМЯ ПО ТИКЕТУ НЕ СОВПАДАЕТ.
3. Сделай выборку только по `symbol = 'AAPL'`.
SELECT
o.symbol,
o.size,
t.price,
o.time AS order_time,
t.time AS price_time
FROM orders o
ASOF LEFT JOIN ticks t ON o.symbol = t.symbol AND o.time >= t.time
WHERE o.symbol = 'AAPL';
ИЛИ
SELECT
o.symbol,
o.size,
t.price,
o.time AS order_time,
t.time AS price_time
FROM
(
SELECT * FROM orders WHERE o.symbol = 'AAPL'
) AS o
ASOF LEFT JOIN
(
SELECT * FROM ticks WHERE o.symbol = 'AAPL'
) AS t
ON o.symbol = t.symbol AND o.time >= t.time;
### **Задача 3.**
Таблица `users`
| user_id | name |
| --- | --- |
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
| 4 | Diana |
Таблица `payments`
| payment_id | user_id | amount |
| --- | --- | --- |
| 1001 | 1 | 500 |
| 1002 | 1 | 1500 |
| 1003 | 3 | 1200 |
| 1004 | 4 | 900 |
1. Верни всех пользователей, у которых **есть платежи** (через `WHERE user_id IN (...)`).
SELECT
u.user_id
FROM users u
WHERE user_id IN (SELECT user_id FROM payments);
2. Добавь условие: сумма платежа больше 1000.
SELECT
u.user_id
FROM users u
WHERE user_id IN (SELECT user_id FROM payments WHERE amount > 1000);
3. Почему это называют `SEMI JOIN`? Как это оптимизируется в ClickHouse?
Потому что это неполноценное соединение , а только проверяющее факт наличия того или иного условия.
Вообще по идее нужно было бы написать LEFT SEMI JOIN , в кликхаус видя конструкцию IN (SELECT...) уже сам понимает что это SEMI JOIN.
### **Задача 4.**
Таблица `big_logs` (упрощённый фрагмент)
| user_id | event_time | event_type |
| --- | --- | --- |
| 1 | 2025-07-17 08:00:00 | login |
| 2 | 2025-07-17 08:05:00 | view |
| 3 | 2025-07-17 08:10:00 | purchase |
| 1 | 2025-07-17 08:20:00 | logout |
| 2 | 2025-07-17 08:30:00 | click |
Таблица `users`
| user_id | name |
| --- | --- |
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
1. Сделай `JOIN`, чтобы добавить `name` к каждому логу.
SELECT
bl.user_id,
bl.event_time,
bl.event_type,
u.name
FROM big_logs bl ANY LEFT JOIN users u ON bl.user_id = u.user_id;
2. Почему `users` нужно ставить **в правую часть JOIN**?
ПОТОМУ ЧТО ЭТА ТАБЛИЦА ЯВЛЯЕТСЯ МАЛЕНЬКОЙ И МОЖНО СКАЗАТЬ СПРАВОЧНОЙ, А ЛОГИ БУДУТ РАСТИ И РАСТИ. И ЕСЛИ ЕЕ ЗАГРУЗИТЬ В ОПЕРАТИВНУЮ ПАМЯТЬ, ТО МЫ МОЖЕМ РАНО ИЛИ ПОЗДНО ПОЛУЧИТЬ ОШИБКУ.
3. Как выбрать `ANY` или `ALL` — если `user_id` уникален?
ЕСЛИ МЫ УВЕРЕНЫ НА 100% ЧТО ОН УНИКАЛЕН ТО НУЖНО ВАЫБИРАТЬ ANY , В ТАКОМ СЛУЧАЕ СОХРАНЯЮТСЯ РЕСУРСЫ ПАМЯТИ. ALL ЖЕ ВЫБИРАЕТСЯ КОГДА НЕОБХОДИМО ДЕКАРТОВО ПРОИЗВЕДЕНИЕ.