практика 'EXPLAIN и EXPLAIN ANALYZE'

This commit is contained in:
mnoskov
2026-03-14 14:09:08 +03:00
parent 508e077da3
commit 50bb355a95
@@ -0,0 +1,203 @@
-- Задание 1
EXPLAIN
SELECT
name, email
FROM
users
WHERE
id = 1;
-- Использует index scan
-- Index Cond: (id = 1) - это значит что условие id = 1, и оно выполняется по индексу, и что id - индекс
-- База использует индекс, потому что у нас по полю id создан индекс, и база выбирает наиболее быстрый пусть ввыполнения запроса - через индекс
-- Задание 2
-- Запрос А
EXPLAIN
SELECT * FROM users WHERE id = 2;
-- Запрос Б
EXPLAIN
SELECT * FROM users WHERE age > 25;
-- В первом запрос index scan, потому что у нас уловие по индексу - id, во втором запросы seq scan, потому что у поля age не индексов, и таблица сканируется медленее
-- Задание 3
EXPLAIN ANALYZE
SELECT
name, price
FROM
products
WHERE
category = 'Электроника';
-- Execution Time: 0.020 ms
-- Тип сканирования: Seq Scan
-- Ожидалось вернуть 1, а вернул 3
-- Задание 4
EXPLAIN ANALYZE
SELECT * FROM users WHERE country = 'RU';
-- Без индекса - Execution Time: 6.769 ms
CREATE INDEX idx_country ON users(country);
-- С индексом - Execution Time: 2.076 ms
-- Сначала идет Bitmap Heap Scan on users - как я понял на этом этапе 'создается' таблица где country = 'RU', а потом Bitmap INdex Scan on idx_country - тут уже мы читам информацию из таблицы где все country = 'RU'.
-- Запрос стал быстрее примерно в три раза
-- Индекс помог, потому что база искала не среди всех данных, а среди 'проиндексированных'
-- Задание 5
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';
-- База исполщовала Nested Loop
-- Чтение началось с orders
-- Execution Time: 0.075 ms
-- Задание 6
CREATE INDEX idx_email ON users(email);
EXPLAIN ANALYZE
SELECT
*
FROM
users
WHERE
lower(email) = 'user_28@example.com';
-- База не использует индекс пока в where есть функция lower
-- Потому что в условии функция, а с ними индексы не в ладах как я понял
-- Чтобы индекс заработал, надо убрать функцию lower, и сравнивать email как есть
-- Если убрать lower, то Execution Time намного быстрее, прям очень намного быстрее
-- Задание 7
CREATE INDEX idx_age ON users(age);
-- Запрос А
EXPLAIN ANALYZE
SELECT * FROM users WHERE age + 5 > 30;
-- Запрос Б
EXPLAIN ANALYZE
SELECT * FROM users WHERE age > 25;
-- Быстрее работает запрос Б, но че то он тоже не хочет индекс использовать, хотя я его создал
-- Первый запрос не может использовать индекс, потому что там в условии математическое вычисление, а почему второй запрос не использует индек - я хз
-- Чтобы исправить запрос надо убрать сложение, и просто написать age > 25, как в запросе Б
-- Задание 8
CREATE INDEX idx_created_at ON users(created_at);
EXPLAIN ANALYZE
SELECT u.name, COUNT(o.id) AS orders_count
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE EXTRACT(YEAR FROM u.created_at) = 2026
GROUP BY u.name;
-- Функция EXTRACT - это плохая идея, потому что это функция которой быть в where по возможности не должно
-- WHERE i.crated_at BETWEEN '2026-01-01' AND '2027-01-01'
-- Индекс не используется в текущеа виде
-- Задание 9
-- Запрос А
EXPLAIN ANALYZE
SELECT * FROM products WHERE price > 50000;
-- Запрос Б
EXPLAIN ANALYZE
SELECT name, price FROM products WHERE price > 50000;
-- Если будет много данных в таблице, то быстрее будет работать второй запрос
-- Второй эффективнее тк в селекте указаны определнные поля, а не все(*)
-- Разница будет особо замета при больших объемах данных
-- Задание 10
EXPLAIN ANALYZE
SELECT u.name, p.name AS product_name, oi.quantity
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 = 'RU' AND p.category = 'Электроника';
-- Порядок чтения таблиц: order_items -> products -> orders -> users
-- Количество строк: order_items - 12, products - 3, orders - 1, users - 0
-- Если у country и category будут индексы, то запрос ьудет выполняться побыстре, потому что будет Index Scan, а не Seq Scan
-- Задание 11
-- До
EXPLAIN ANALYZE
SELECT *
FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE LOWER(u.name) LIKE '%иван%'
AND EXTRACT(MONTH FROM o.order_date) = 1
AND u.age + 10 > 35;
-- Execution Time: 0.219 ms
-- После
EXPLAIN ANALYZE
SELECT *
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.name = 'иван' AND
o.order_date BETWEEN '2024-01-01' AND '2024-02-01' AND
O.order_date BETWEEN '2026-01-01' AND '2026-02-01' AND
u.age > 25;
-- Execution Time: 0.032 ms
-- Мой вариант лучще, потому что у меня нет функций и вычисление мешаюзих использовать индексы в условии, и оптимизатор может успешно использовать индексы
-- Задание 12
-- Запрос 1
EXPLAIN ANALYZE
SELECT
o.user_id,
o.id AS order_id
FROM
users u
JOIN
orders o ON u.id = o.user_id AND u.country = 'RU';
-- Запрос 2
EXPLAIN ANALYZE
SELECT
o.user_id,
o.id AS order_id
FROM
orders o
WHERE EXISTS (
SELECT
1
FROM
users u
WHERE
o.user_id = u.id AND
u.country = 'RU'
);
-- Запрос 3
EXPLAIN ANALYZE
SELECT
o.user_id,
o.id AS order_id
FROM
orders o
WHERE o.user_id IN (
SELECT
u.id
FROM
users u
WHERE
u.country = 'RU'
);
-- Запрос 1: Execution Time: 0.055 ms
-- Запрос 2: Execution Time: 0.051 ms
-- Запрос 3: Execution Time: 0.073 ms
-- Они все дют примерно одинаковый разультат, потому что мало данных в таблице. А планы выполнения у них у всех одинаковые, вот прям 1 в 1. Ну по логие 3 запрос самый медленный, а первые два шустрые