Реалізація партиціонування таблиць бази даних

Наша компанія займається розробкою, підтримкою та обслуговуванням сайтів будь-якої складності. Від простих односторінкових сайтів до масштабних кластерних систем, побудованих на мікро сервісах. Досвід розробників підтверджено сертифікатами від вендорів.

Розробка та обслуговування будь-яких видів сайтів:

Інформаційні сайти або веб-програми
Сайти візитки, landing page, корпоративні сайти, онлайн каталоги, квіз, промо-сайти, блоги, ресурси новин, інформаційні портали, форуми, агрегатори
Сайти або веб-програми електронної комерції
Інтернет-магазини, B2B-портали, маркетплейси, онлайн-обмінники, кешбек-сайти, біржі, дропшиппінг-платформи, парсери товарів
Веб-програми для управління бізнес-процесами
CRM-системи, ERP-системи, корпоративні портали, системи управління виробництвом, парсери інформації
Сайти або веб-програми електронних послуг
Дошки оголошень, онлайн-школи, онлайн-кінотеатри, конструктори сайтів, портали надання електронних послуг, відеохостинги, тематичні портали

Це лише деякі з технічних типів сайтів, з якими ми працюємо, і кожен із них може мати свої специфічні особливості та функціональність, а також бути адаптованим під конкретні потреби та цілі клієнта.

Пропоновані послуги
Показано 1 з 1 послугУсі 2065 послуг
Реалізація партиціонування таблиць бази даних
Складна
~3-5 робочих днів
Часті питання

Наші компетенції:

Етапи розробки

Останні роботи

  • image_website-b2b-advance_0.png
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Розробка веб-сайту для компанії ФІКСПЕР
    851

Реалізація партиціонування таблиць бази даних

Партиціонування — це розбиття однієї логічної таблиці на фізично окремі частини (партиції) за значенням ключа. Запит SELECT * FROM events WHERE created_at > '2025-01-01' на нерозбитій таблиці з 500 мільйонів рядків сканує все. На розбитій за місяцями — тільки одну з ~40 мільйонів рядків. Плюс кожну партицію можна незалежно архівувати, переносити на дешеве сховище або видаляти.

PostgreSQL: декларативне партиціонування

З версії PostgreSQL 10 партиціонування вбудоване і не потребує тригерів.

Range партиціонування за датою

-- Створюємо батьківську таблицю
CREATE TABLE events (
    id          BIGSERIAL,
    user_id     INTEGER NOT NULL,
    event_type  VARCHAR(64) NOT NULL,
    payload     JSONB,
    created_at  TIMESTAMPTZ NOT NULL DEFAULT now()
) PARTITION BY RANGE (created_at);

-- Створюємо партиції — по одному місяцю
CREATE TABLE events_2025_01 PARTITION OF events
    FOR VALUES FROM ('2025-01-01') TO ('2025-02-01');

CREATE TABLE events_2025_02 PARTITION OF events
    FOR VALUES FROM ('2025-02-01') TO ('2025-03-01');

-- Кожна партиція має свої індекси
CREATE INDEX ON events_2025_01 (user_id, created_at DESC);
CREATE INDEX ON events_2025_02 (user_id, created_at DESC);

-- Індекс на батьківській таблиці автоматично створюється на всіх партиціях (PG 11+)
CREATE INDEX ON events (user_id, created_at DESC);

Hash партиціонування (рівномірний розподіл)

CREATE TABLE user_sessions (
    id          UUID DEFAULT gen_random_uuid(),
    user_id     INTEGER NOT NULL,
    data        JSONB,
    created_at  TIMESTAMPTZ DEFAULT now()
) PARTITION BY HASH (user_id);

-- 8 партицій для рівномірного розподілу
DO $$
BEGIN
    FOR i IN 0..7 LOOP
        EXECUTE format(
            'CREATE TABLE user_sessions_%s PARTITION OF user_sessions
             FOR VALUES WITH (MODULUS 8, REMAINDER %s)',
            i, i
        );
    END LOOP;
END $$;

List партиціонування за значенням

CREATE TABLE orders (
    id          BIGSERIAL,
    country     CHAR(2) NOT NULL,
    status      VARCHAR(32),
    total       NUMERIC(12,2),
    created_at  TIMESTAMPTZ DEFAULT now()
) PARTITION BY LIST (country);

CREATE TABLE orders_ua PARTITION OF orders FOR VALUES IN ('UA');
CREATE TABLE orders_ru PARTITION OF orders FOR VALUES IN ('RU');
CREATE TABLE orders_by PARTITION OF orders FOR VALUES IN ('BY');
CREATE TABLE orders_other PARTITION OF orders DEFAULT; -- для всіх інших

Автоматичне створення партицій

Створювати партиції вручну кожен місяць — ненадійно. Автоматизація через pg_partman:

# Встановлення розширення
apt-get install postgresql-14-partman

# У PostgreSQL
CREATE EXTENSION pg_partman SCHEMA partman;

-- Налаштування автоматичного управління
SELECT partman.create_parent(
    p_parent_table   => 'public.events',
    p_control        => 'created_at',
    p_type           => 'native',
    p_interval       => 'monthly',
    p_premake        => 3  -- створювати 3 партиції вперед
);

-- Оновлюємо конфігурацію
UPDATE partman.part_config
SET retention            = '12 months',  -- видаляти партиції старше 12 місяців
    retention_keep_table = false,         -- видаляти фізично, не тільки відсоединювати
    infinite_time_partitions = true
WHERE parent_table = 'public.events';

Запуск обслуговування (додавання нових + видалення старих партицій):

# cron: кожен день о 2:00
0 2 * * * psql -d mydb -c "SELECT partman.run_maintenance_proc();"

MySQL: партиціонування

MySQL підтримує партиціонування, але з обмеженнями: всі унікальні ключі повинні включати ключ партиціонування.

CREATE TABLE orders (
    id         BIGINT NOT NULL AUTO_INCREMENT,
    user_id    INT NOT NULL,
    status     VARCHAR(32),
    total      DECIMAL(12,2),
    created_at DATETIME NOT NULL,
    PRIMARY KEY (id, created_at),  -- created_at обов'язковий у PK для partition by range
    KEY idx_user_id (user_id)
)
PARTITION BY RANGE (YEAR(created_at) * 100 + MONTH(created_at)) (
    PARTITION p202501 VALUES LESS THAN (202502),
    PARTITION p202502 VALUES LESS THAN (202503),
    PARTITION p202503 VALUES LESS THAN (202504),
    PARTITION p_future VALUES LESS THAN MAXVALUE
);

Додавання партиції перед закінченням попередньої:

-- Перед додаванням нової партиції — видалити MAXVALUE
ALTER TABLE orders REORGANIZE PARTITION p_future INTO (
    PARTITION p202504 VALUES LESS THAN (202505),
    PARTITION p_future VALUES LESS THAN MAXVALUE
);

Partition Pruning: впевніємось, що він працює

-- PostgreSQL: перевіряємо, що використовується partition pruning
EXPLAIN SELECT * FROM events
WHERE created_at BETWEEN '2025-01-01' AND '2025-01-31';

-- Повинно бути: "Seq Scan on events_2025_01"
-- (не "Seq Scan on events" що означає сканування всієї таблиці)