Files
homework/mnoskov/Теория БД/1. Ускорение и масштабирование/2. Партиции/practice_partitions.sql
T

189 lines
8.3 KiB
SQL
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* Задание 1. Какой вид партиционирования выбрать
1)
* range по полю order_date
* запросы с between в год
1. where order_date >= '2022-01-01' and order_date < '2023-01-01'
2. where extract('year' from order_date) = '2025'
2)
* тут два типа партиционирования подходят. range по created_at или list по country.
* если выбирать list по country то плюс - это при фильтрах по стране будут отсекаться лишние партиции, а минус, что год/месяц регистрации не будет разделен по партициям.
3)
* логично range по created_at - чтобы разделить по месяцам/годам, а hash по user_id - почему так, точно сказать не могу, но в теории сказано что hash используется когда нет диапазона или списка и это частый сценарий для логов
* с range выиграют запросы с фильтрами по created_at, а с hash выигают запросы с фильтрами по user_id, а все что не указаны как поле для партиций, не почувствуют разницы.*/
/* Задание 2. Размер партиций
2) количество партициый за 10 лет по:
* годам - 10, тут вообще все четко, и удалять не сложно, и поддержка проще, и запросы будут хорошо делаться
* месяцам - 120, тут с удалением тарых данных труднее, поддержка тяжелая, но скорость запросов будет лучше, если фильтрация будет по месяцам
* дням - примерно 3650, а это я чувствую пиздец, с удалением и поддержкой жопа, и со скоростью запросов тоже жопа - данные будут читаться из кучи партиций что не есть хорошо
3)
Я думаю прям для очень большого магазина оптимальнее будет партиционирование по месяцам - тк очень много покупателей и большинство статистик будет по месяцам, по годам тоэе конечно, но думаю приоритетнее по месяцам*/
-- Задание 3. RANGE‑партиции по дате заказов
DROP TABLE IF EXISTS orders_part;
CREATE TABLE orders_part (
id bigint,
user_id bigint,
order_date timestamptz NOT NULL,
status varchar(20),
PRIMARY KEY (id, order_date),
FOREIGN KEY (user_id) REFERENCES users_1(id)
) PARTITION BY RANGE (order_date);
CREATE TABLE orders_2024 PARTITION OF orders_part
FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
CREATE TABLE orders_2025 PARTITION OF orders_part
FOR VALUES FROM ('2025-01-01') TO ('2026-01-01');
CREATE TABLE orders_2026 PARTITION OF orders_part
FOR VALUES FROM ('2026-01-01') TO ('2027-01-01');
-- сделал insert который попросил сгенерировать нейронку
EXPLAIN ANALYZE
SELECT
*
FROM
orders_part
WHERE
order_date BETWEEN '2025-01-01' AND '2025-12-31 23:59:59'; -- пришлось сделать так, тк дата 2026-01-01 тоже есть в таблице
-- в этом запросе за год - читатется только одна партиция - orders_2025, НО если в условии все же написать AND '2026-01-01', то читаются две партиции orders_2025 и orders_2026 и время выполнения запроса намного больше тк выполняется full scan обеих таблиц
EXPLAIN ANALYZE
SELECT
*
FROM
orders_part
WHERE
EXTRACT('year' FROM order_date) IN ('2024', '2025'); -- так читаются все три партиции, 2026 почему-то тоже захватывается, но по итогу после сканирование у таблицы orders_2026 - rows = 0
EXPLAIN ANALYZE
SELECT
*
FROM
orders_part;
-- так просто сканируются все три партиции, но без фильтров, как было в предидущем варианте
-- Задание 4. LIST‑партиции по стране пользователей
DROP TABLE IF EXISTS users_part;
CREATE TABLE users_part (
id int8 NOT NULL,
"name" varchar(100) NOT NULL,
age int2 NULL,
email varchar(100) NULL,
country bpchar(2) NULL,
is_active bool NULL,
created_at timestamptz NOT NULL,
PRIMARY KEY (id, country)
) PARTITION BY LIST (country);
CREATE TABLE users_ru PARTITION OF users_part
FOR VALUES IN ('RU');
CREATE TABLE users_us PARTITION OF users_part
FOR VALUES IN ('US');
CREATE TABLE users_gb PARTITION OF users_part
FOR VALUES IN ('GB');
CREATE TABLE users_de PARTITION OF users_part
FOR VALUES IN ('DE');
CREATE TABLE users_fr PARTITION OF users_part
FOR VALUES IN ('FR');
CREATE TABLE users_jp PARTITION OF users_part
FOR VALUES IN ('JP');
CREATE TABLE users_uk PARTITION OF users_part
FOR VALUES IN ('UK');
CREATE TABLE users_kz PARTITION OF users_part
FOR VALUES IN ('KZ');
-- сделал insert который попросил сгенерировать нейронку
EXPLAIN ANALYZE
SELECT
*
FROM
users_part
WHERE
country = 'RU';
-- запрос скаинровал только партицию users_ru
EXPLAIN ANALYZE
SELECT
*
FROM
users_part
WHERE
country IN ('RU', 'KZ');
-- запрос сканировал только партиции users_ru и users_kz
EXPLAIN ANALYZE
SELECT
*
FROM
users_part
WHERE
age BETWEEN 44 AND 66;
-- сканировал не просто users_part, а каждую партицию по отдельности
-- Задание 5. HASH‑партиции по user_id в логах
DROP TABLE IF EXISTS user_logs_part;
CREATE TABLE user_logs_part (
id int8,
user_id bigint NOT NULL,
created_at timestamp NOT null,
event_type text NOT NULL,
payload jsonb,
PRIMARY KEY (id, user_id)
) PARTITION BY hash (user_id);
CREATE TABLE user_logs_p1 PARTITION OF user_logs_part
FOR VALUES WITH (modulus 4, remainder 0);
CREATE TABLE user_logs_p2 PARTITION OF user_logs_part
FOR VALUES WITH (modulus 4, remainder 1);
CREATE TABLE user_logs_p3 PARTITION OF user_logs_part
FOR VALUES WITH (modulus 4, remainder 2);
CREATE TABLE user_logs_p4 PARTITION OF user_logs_part
FOR VALUES WITH (modulus 4, remainder 3);
-- сделал insert который попросил сгенерировать нейронку
EXPLAIN ANALYZE
SELECT * FROM user_logs_part WHERE user_id = 228;
-- читает только user_logs_p2
EXPLAIN ANALYZE
SELECT * FROM user_logs_part WHERE created_at >= current_date - INTERVAL '7 days';
-- читает все партиции
-- Задание 6
-- email, чтобы искать пользователя быстрее, created_at для сортировки и where
CREATE UNIQUE INDEX idx_users_ru_email ON users_ru(email);
CREATE INDEX idx_users_ru_created_at ON users_ru(created_at);
CREATE UNIQUE INDEX idx_users_us_email ON users_us(email);
CREATE INDEX idx_users_us_created_at ON users_us(created_at);
CREATE UNIQUE INDEX idx_users_gb_email ON users_gb(email);
CREATE INDEX idx_users_gb_created_at ON users_gb(created_at);
CREATE UNIQUE INDEX idx_users_de_email ON users_de(email);
CREATE INDEX idx_users_de_created_at ON users_de(created_at);
CREATE UNIQUE INDEX idx_users_fr_email ON users_fr(email);
CREATE INDEX idx_users_fr_created_at ON users_fr(created_at);
CREATE UNIQUE INDEX idx_users_jp_email ON users_jp(email);
CREATE INDEX idx_users_jp_created_at ON users_jp(created_at);
CREATE UNIQUE INDEX idx_users_uk_email ON users_uk(email);
CREATE INDEX idx_users_uk_created_at ON users_uk(created_at);
CREATE UNIQUE INDEX idx_users_kz_email ON users_kz(email);
CREATE INDEX idx_users_kz_created_at ON users_kz(created_at);
-- должны ускориться запросы с поиском пользователей по email, и запросы с сортировкой по дате или с фильтрацией по интервалам