сделал DDL для пет проекта
This commit is contained in:
+217
@@ -0,0 +1,217 @@
|
||||
-- Задание 1
|
||||
EXPLAIN ANALYZE
|
||||
SELECT country, count(*) AS users_count
|
||||
FROM users
|
||||
WHERE is_active = TRUE
|
||||
GROUP BY country
|
||||
HAVING count(*) > 1
|
||||
ORDER BY users_count DESC;
|
||||
-- WHERE применится до GROUP BY
|
||||
-- HAVING применится после GROUP BY
|
||||
-- Использовать users_count в HAVING нельзя, а в ORDER BY можно
|
||||
|
||||
|
||||
-- Задание 2
|
||||
EXPLAIN ANALYZE
|
||||
SELECT u.name, o.order_date, o.status
|
||||
FROM users u
|
||||
JOIN orders o ON u.id = o.user_id
|
||||
WHERE u.country = 'RU' AND o.status = 'paid'
|
||||
ORDER BY o.order_date DESC;
|
||||
-- Порядок выполнения по QUERY PLAN:
|
||||
-- 1) сначала сканирутся таблица orders и выполняется фильтрация o.status = 'paid',
|
||||
-- 2) потом сканируется таблица users по условию u.id = o.user_id, и выполняется вильтрация u.country = 'RU',
|
||||
-- 3) далее Nested Loop соединяет orders и users, которые уже прошли фильтры,
|
||||
-- 4) теперь выводится выполняется сортирвка o.order_date DESC
|
||||
|
||||
-- Порядок выполнения по логике:
|
||||
-- 1) сначала сканируем таблицу users и присоединяем orders по условию u.id = o.user_id
|
||||
-- 2) потом фильтруем соединенные таблицы по u.country = 'RU' и o.status = 'paid'
|
||||
-- 3) в SELECT выбираем поля которые хотим вывести - u.name, o.order_date, o.status
|
||||
-- 4) сортируем выбранные поля по o.order_date по убыванию
|
||||
|
||||
|
||||
-- Задание 3
|
||||
-- Запрос А
|
||||
SELECT country, AVG(age) AS avg_age
|
||||
FROM users
|
||||
GROUP BY country
|
||||
HAVING country = 'Россия';
|
||||
-- Работает медленно потому having фильтрет после группировки а не до
|
||||
|
||||
-- Запрос Б
|
||||
SELECT country, avg(age) AS avg_age
|
||||
FROM users
|
||||
WHERE country = 'RU'
|
||||
GROUP BY country;
|
||||
-- Этот вариант быстрее, тк он фильтрует строки до группировки, те группируется меньше строк а не все
|
||||
|
||||
|
||||
-- Задание 4
|
||||
-- Запрос А
|
||||
EXPLAIN ANALYZE
|
||||
SELECT category, AVG(price) AS avg_price
|
||||
FROM products
|
||||
GROUP BY category
|
||||
HAVING category = 'Электроника' AND AVG(price) > 20000;
|
||||
|
||||
-- Запрос Б
|
||||
EXPLAIN ANALYZE
|
||||
SELECT category, AVG(price) AS avg_price
|
||||
FROM products
|
||||
WHERE category = 'Электроника'
|
||||
GROUP BY category
|
||||
HAVING AVG(price) > 20000;
|
||||
-- Количество обработанных строк у запроса А: 4
|
||||
-- Количество обработанных строк у запроса Б: 4
|
||||
-- PostgreSQL походу оптимизирует даже хуйню написанную в запросе А, планы запросов А и Б одинаковые - 1 в 1, хотя по сути у запроса А должно быть больше строк
|
||||
|
||||
|
||||
-- Задание 5
|
||||
-- Изначальный запрос
|
||||
SELECT
|
||||
country,
|
||||
COUNT(*) AS users_count
|
||||
FROM users
|
||||
WHERE users_count > 1
|
||||
GROUP BY country
|
||||
ORDER BY country;
|
||||
|
||||
-- Исправленный запрос
|
||||
SELECT
|
||||
country,
|
||||
COUNT(*) AS users_count
|
||||
FROM users
|
||||
GROUP BY country
|
||||
HAVING COUNT(*) > 1
|
||||
ORDER BY country;
|
||||
|
||||
-- Задание 6
|
||||
SELECT
|
||||
u.country,
|
||||
COUNT(o.id) AS orders_count,
|
||||
AVG(o.id) AS avg_order_id
|
||||
FROM users u
|
||||
LEFT JOIN orders o ON u.id = o.user_id
|
||||
WHERE u.is_active = true
|
||||
GROUP BY u.country
|
||||
HAVING COUNT(o.id) > 1
|
||||
ORDER BY orders_count DESC
|
||||
LIMIT 3;
|
||||
-- Полный порядок выполнения:
|
||||
-- 1) FROM/JOIN - сканируется таблица users, и к ней присоединяется таблица orders по условию u.id = o.user_id
|
||||
-- 2) WHERE - из двух соединенных таблиц фильтруются и остаются только строки где u.is_active = true
|
||||
-- 3) GROUP BY - происходится группировка по u.country, те все строки с одной и той же страной(записью в столбце) сжимаются в одну
|
||||
-- 4) HAVING - уже по сгруппированным строкам проводится фильтрация по COUNT(o.id) > 1, остются только те страны(строки) где кол-во пользователей больше одного
|
||||
-- 5) SELECT - выбираются столбцы которые будут выведены: u.country, COUNT(o.id) AS orders_count, AVG(o.id) AS avg_order_id
|
||||
-- 6) ORDER BY - выбранные в SELECT строки сортируются по orders_count по убыванию
|
||||
-- 7) LIMIT - из отсортированных строк остаются только первые 3
|
||||
|
||||
|
||||
-- Задание 7
|
||||
-- Запрос А
|
||||
EXPLAIN ANALYZE
|
||||
SELECT category, COUNT(*)
|
||||
FROM products
|
||||
GROUP BY category
|
||||
HAVING category = 'Электроника';
|
||||
|
||||
-- Запрос Б
|
||||
EXPLAIN ANALYZE
|
||||
SELECT category, COUNT(*)
|
||||
FROM products
|
||||
WHERE category = 'Электроника'
|
||||
GROUP BY category;
|
||||
-- по логике запрос Б должен быть быстрее тк он сначала филтрует строки а потом группирует уже отфильтрованное,
|
||||
-- НО PostgreSql может оптимизровать и запрос А, и получается что выполняются оба запроса одинаково, сначала фильтрация а потом группировка
|
||||
-- В обоих запросах на шаге 'Seq Scan on products' обрабатываются: 3 строки, а на 'GroupAggregate': 1 строка
|
||||
-- Execution Time одно и тоже
|
||||
|
||||
|
||||
-- Задание 8
|
||||
SELECT
|
||||
u.name,
|
||||
COUNT(o.id) AS orders_count
|
||||
FROM users u
|
||||
LEFT JOIN orders o ON u.id = o.user_id
|
||||
WHERE u.country = 'Россия'
|
||||
AND u.age > 25
|
||||
AND o.status = 'completed'
|
||||
GROUP BY u.name
|
||||
HAVING COUNT(o.id) >= 2
|
||||
ORDER BY orders_count DESC;
|
||||
-- WHERE применяется между FROM/JOIN и GROUP BY
|
||||
-- HAVING применяется между GROUP BY и SELECT
|
||||
-- фильтрация по o.status в WHERE происходит группировки строк, а фильтрация по COUNT(o.id) в HAVING происходит уже после группирациюю, по самим сгруппированным строкам
|
||||
|
||||
|
||||
-- Задание 9
|
||||
SELECT
|
||||
u.name,
|
||||
p.name AS product_name,
|
||||
p.price
|
||||
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 = 'Россия'
|
||||
ORDER BY p.price DESC
|
||||
LIMIT 5;
|
||||
-- ORDER BY применяется после SELECT, перед LIMIT/OFFSET(если есть)
|
||||
-- LIMIT идет после GROUP BY, тк сначала нужно отфильтровать строки чтобы взять их кусок(5 строк)
|
||||
-- если LIMIT(5) выполнить до сортировки, то это будет бесполезно, возьмутся просто первые 5 строк, и уже они будут сортироваться, и по итогу выйдет хуйня
|
||||
|
||||
|
||||
-- Задание 10
|
||||
EXPLAIN ANALYZE
|
||||
SELECT
|
||||
category,
|
||||
count(id) AS count_product_in_category,
|
||||
avg(price) AS avg_category_price
|
||||
FROM
|
||||
products
|
||||
GROUP BY
|
||||
category
|
||||
HAVING
|
||||
count(id) >= 2 OR avg(price) > 15000
|
||||
ORDER BY
|
||||
avg_category_price DESC
|
||||
LIMIT 3;
|
||||
-- 1) FROM - сканируем poducts
|
||||
-- 2) GROUP BY - группируем по category
|
||||
-- 3) HAVING - фильтруем по агрегированной функции count(id)
|
||||
-- 4) SELECT - делаем выборку по столбцам category, count_product_in_category, avg_category_price
|
||||
-- 5) ORDER BY - сортируем по avg_category_price по убыванию
|
||||
-- 6) LIMIT - выбираем первые 3 строки из отсортированных
|
||||
-- Ипсользовал HAVING тк по условию все фильтрации по агрегированным функциям
|
||||
-- Выполнил с EXPLAIN ANALYZE, сначала читаетя porducts, потом делается фильтрации по count(id) >= 2 и avg(price) > 15000, далее sort, а потом Limit
|
||||
|
||||
|
||||
-- Задание 11
|
||||
-- Запрос А
|
||||
EXPLAIN ANALYZE
|
||||
SELECT
|
||||
u.name,
|
||||
u.age,
|
||||
(SELECT COUNT(*)
|
||||
FROM orders o
|
||||
WHERE o.user_id = u.id) AS orders_count
|
||||
FROM users u
|
||||
WHERE u.country = 'RU'
|
||||
ORDER BY orders_count DESC;
|
||||
-- Подзапрос в SELECT выполняется самым первым, до начала остального запроса, и называется в планировщие - SubPlan 1
|
||||
-- orders_count нельзя использовать в WHERE
|
||||
-- orders_count можно использовать в ORDER BY
|
||||
|
||||
-- Запрос Б(исправленный)
|
||||
EXPLAIN ANALYZE
|
||||
SELECT
|
||||
u.name,
|
||||
u.age,
|
||||
count(o.id) AS orders_count
|
||||
FROM users u
|
||||
LEFT JOIN orders o ON u.id = o.user_id
|
||||
WHERE u.country = 'RU'
|
||||
GROUP BY u.name, u.age
|
||||
ORDER BY orders_count DESC;
|
||||
-- Запрос Б(исправленный) - быстрее, тк подзапрос в SELECT делается для каждого пользователя заново, а JOIN всего один раз
|
||||
Reference in New Issue
Block a user