практика 'Партиции'
This commit is contained in:
@@ -0,0 +1,190 @@
|
||||
/* Задание 1. Какой вид партиционирования выбрать
|
||||
1)
|
||||
* range по полю order_date
|
||||
* запросы с between в год
|
||||
1. where order_date between '2022-01-01' and '2023-01-01'
|
||||
2. where extract('year' from order_date) = '2025'
|
||||
3. where order_date < '2026-01-01' and order_date > '2025-01-01'
|
||||
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, и запросы с сортировкой по дате или с фильтрацией по интервалам
|
||||
Reference in New Issue
Block a user