171 lines
10 KiB
SQL
171 lines
10 KiB
SQL
- Задание 1. Какой вид партиционирования выбрать
|
||
|
||
**Ответ текстом.**
|
||
|
||
1. Таблица `orders(id, user_id, order_date, status)` — очень большая (10 лет истории).
|
||
- Какой вид партиционирования (RANGE / LIST / HASH) ты выберешь и по какому полю?
|
||
ДУМАЮ МОЖНО СДЕЛАТЬ 2 ПАРТИЦИИ, ПЕРВАЯ RANGE ПО ПОЛЯМ USER_ID И ORDER_DATE - RANGE. И ВТОРАЯ ПАРТИЦИЯ ПО USER_ID И STATUS - LIST
|
||
|
||
- Какие типы запросов выиграют от этого выбора? Приведи 3 примера запросов.
|
||
|
||
|
||
2. Таблица `users(id, name, age, email, country, is_active, created_at)` — много пользователей по разным странам.
|
||
- Выбери вид партиционирования (можно «не партиционировать») и обоснуй.
|
||
МОЖНО ПО АЙДИ И СТРАНЕ - LIST. ПО АЙДИ И CREATE_AT - RANGE. COUNTRY И IS_ACTIVE - ЧТОБЫ ПОНИМАТЬ В КАКОЙ СТРАНЕ БОЛЬШЕ АКТИВНЫХ ПОЛЬЗОВАТЕЛЕЙ - МОЖЕТ HASH?
|
||
|
||
- Если ты выбрал LIST по `country`, какие плюсы и минусы у такого решения?
|
||
Огромное количество стран - минус.
|
||
|
||
3. Таблица логов `user_logs(id, user_id, created_at, event_type, payload)` — миллионы записей в день.
|
||
- Какой вид партиционирования по какому полю логичен (RANGE / HASH) и почему?
|
||
USER_ID и EVENT_TYPE по LIST или по HASH.
|
||
|
||
- Задание 2. Размер партиций
|
||
|
||
**Ответ текстом.**
|
||
|
||
1. Для `orders` с партиционированием по `order_date` придумай три варианта:
|
||
- партиции по годам;
|
||
- по месяцам;
|
||
- по дням.
|
||
2. Для каждого варианта напиши:
|
||
- примерно сколько будет партиций за 10 лет;
|
||
по годам - 10 * 1 = 10, по месяцам - 10 * 12 = 120, по дням 366 * 2 + 365 * 4 = 2652.
|
||
|
||
- плюсы и минусы (удаление старых данных, поддержка, скорость запросов).
|
||
|
||
3. Выбери один вариант и обоснуй: почему он оптимален для большого онлайн‑магазина.
|
||
Для онлайн магазина лучше подойдет по месяцам, чтобы понимать сезонность товаров.
|
||
|
||
- Задание 3. RANGE‑партиции по дате заказов
|
||
|
||
**Уточнение**: партиционировать уже существующую таблицу муторно, проще создать новую
|
||
|
||
**Сделать в PostgreSQL:**
|
||
|
||
- создать партиционированную таблицу `orders`, разбитую методом RANGE по полю `order_date`;
|
||
CREATE TABLE orderz (
|
||
id INT GENERATED ALWAYS AS IDENTITY,
|
||
user_id INT NOT NULL,
|
||
order_date DATE NOT NULL,
|
||
status TEXT NOT NULL,
|
||
PRIMARY KEY (id, order_date)
|
||
) PARTITION BY RANGE(order_date);
|
||
|
||
- создать несколько партиций (например, по годам или другим диапазонам дат), чтобы вставка строк с разными датами автоматически попадала в нужную партицию;
|
||
CREATE TABLE orderz_2023 PARTITION OF orderz
|
||
FOR VALUES FROM ('2023-01-01') TO ('2024-01-01');
|
||
|
||
CREATE TABLE orderz_2024 PARTITION OF orderz
|
||
FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
|
||
|
||
CREATE TABLE orderz_2025 PARTITION OF orderz
|
||
FOR VALUES FROM ('2025-01-01') TO ('2026-01-01');
|
||
|
||
CREATE TABLE orderz_before_2023 PARTITION OF orderz
|
||
FOR VALUES FROM ('2000-01-01') TO ('2023-01-01');
|
||
- вставить тестовые данные с разными датами;
|
||
INSERT INTO orderz (user_id, order_date, status)
|
||
VALUES
|
||
(1, '2023-04-06', 'paid'),
|
||
(2, '2024-07-17', 'decline'),
|
||
(3, '2007-11-27', 'error');
|
||
|
||
- Написать несколько запросов выборки (за один год, за несколько лет, за весь период)
|
||
|
||
SELECT *
|
||
FROM orderz o
|
||
WHERE order_date BETWEEN ('2023-01-01') AND ('2023-12-31');
|
||
|
||
SELECT *
|
||
FROM orderz o
|
||
WHERE order_date BETWEEN ('2022-01-01') AND ('2024-12-31');
|
||
|
||
SELECT *
|
||
FROM orderz o;
|
||
|
||
- Объяснить, в каких случаях БД будет читать только часть партиций, а в каких — все.
|
||
Если мы выставляем определенное условие соответствующее одной партиции, то чтение будет по этой же партиции, если выставляем по нескольким, то чтение по нескольким.
|
||
|
||
- Задание 4. LIST‑партиции по стране пользователей
|
||
|
||
**Сделать в PostgreSQL:**
|
||
|
||
- создать партиционированную таблицу `users`, разделённую методом LIST по полю `country`;
|
||
CREATE TABLE userz (
|
||
id INT PRIMARY KEY,
|
||
name TEXT NOT NULL,
|
||
age INT,
|
||
email TEXT NOT NULL,
|
||
country TEXT NOT NULL,
|
||
is_active BOOLEAN NOT NULL,
|
||
created_at TIMESTAMP NOT NULL
|
||
) PARTITION BY LIST (country);
|
||
|
||
- определить несколько партиций для разных стран или групп стран и вставить тестовые данные так, чтобы строки автоматически распределялись по этим партициям;
|
||
|
||
CREATE TABLE userz_ru PARTITION OF userz
|
||
FOR VALUES IN ('RU');
|
||
|
||
CREATE TABLE userz_us PARTITION OF userz
|
||
FOR VALUES IN ('US');
|
||
|
||
CREATE TABLE userz_other PARTITION OF userz
|
||
FOR VALUES IN (DEFAULT);
|
||
- написать запросы выборки:
|
||
- по конкретной стране (например, только пользователи из одной страны);
|
||
SELECT *
|
||
FROM userz u
|
||
WHERE country = 'RU';
|
||
|
||
- по условию, не связанному с `country` (например, все активные пользователи);
|
||
SELECT *
|
||
FROM userz u
|
||
WHERE status = 'is_active';
|
||
|
||
- Объясни, для какого запроса PostgreSQL может обращаться только к одной/нескольким партициям, а для какого придётся просматривать все партиции.
|
||
Первый запрос обращается именно к одной партиции, а второй уже ко всем, потому что вто второй нет условия по партиции 'RU'.
|
||
|
||
- Задание 5. HASH‑партиции по user_id в логах
|
||
|
||
**Сделать в PostgreSQL:**
|
||
|
||
- создать таблицу `user_logs`, партиционированную методом HASH по полю `user_id`, с несколькими партициями;
|
||
CREATE TABLE user_logz (
|
||
id BIGSERIAL PRIMARY KEY,
|
||
user_id BIGINT NOT NULL,
|
||
created_at TIMESTAMP NOT NULL,
|
||
event_type TEXT NOT NULL,
|
||
payload JSONB
|
||
) PARTITION BY HASH (user_id);
|
||
|
||
CREATE TABLE user_logz_p0 PARTITION OF user_logz
|
||
FOR VALUES WITH (MODULUS 4, REMAINDER 0);
|
||
|
||
CREATE TABLE user_logz_p1 PARTITION OF user_logz
|
||
FOR VALUES WITH (MODULUS 4, REMAINDER 1);
|
||
|
||
CREATE TABLE user_logz_p2 PARTITION OF user_logz
|
||
FOR VALUES WITH (MODULUS 4, REMAINDER 2);
|
||
|
||
CREATE TABLE user_logz_p3 PARTITION OF user_logz
|
||
FOR VALUES WITH (MODULUS 4, REMAINDER 3);
|
||
|
||
- заполнить таблицу тестовыми строками с разными значениями `user_id`;
|
||
INSERT INTO user_logz (user_id, created_at, event_type, payload)
|
||
VALUES (10, now(), 'login', '{"ip": "127.0.0.1"}');
|
||
|
||
SELECT * FROM user_logz
|
||
WHERE created_at >= now() - interval '1 day';
|
||
|
||
- написать запрос:
|
||
- выборки всех логов по конкретному `user_id`;
|
||
SELECT * FROM user_logz WHERE user_id = 10;
|
||
|
||
- выборки всех логов за период по полю `created_at` (без фильтра по `user_id`);
|
||
SELECT * FROM user_logz
|
||
WHERE created_at >= now() - interval '1 day';
|
||
|
||
- Объясни какой запрос позволит серверу обратиться только к одной партиции, а какой заставит сканировать все партиции и почему.
|
||
Первый запрос обращается к одной партиции потому что есть условие по партиционному полю, второй именно ко всем таблицам, потому что нет условия по партиции.
|