Table Partitioning — RANGE, LIST, HASH
buyurtmalar jadvalida 500 million qator. So'rovlar sekinlashgan, index ham yordam bermayapti. Sabab — index juda katta, to'liq skanlanmoqda.
Yechim — jadvalni fizik bo'laklarga bo'lish: Table Partitioning. Har yilgi buyurtmalar alohida bo'lakda — 2024 yil so'rovida faqat 2024 bo'lagi skanlanadi.
Partitioning nima?
Katta jadvalni kichik bo'laklarga (partition) bo'lish. Logik jihatdan bitta jadval, fizik jihatdan ko'p bo'lak.
buyurtmalar (ota jadval)
├── buyurtmalar_2022 (2022 yil qatorlari)
├── buyurtmalar_2023 (2023 yil qatorlari)
└── buyurtmalar_2024 (2024 yil qatorlari)
2024 yil so'rovida faqat buyurtmalar_2024 ko'rib chiqiladi — 10 barobar tez.
RANGE Partitioning — oraliq bo'yicha
Sana, son oraliqlari uchun:
CREATE TABLE buyurtmalar (
id BIGSERIAL,
sana DATE NOT NULL,
summa NUMERIC,
PRIMARY KEY (id, sana)
) PARTITION BY RANGE (sana);
-- Yillik bo'laklar
CREATE TABLE buyurtmalar_2022
PARTITION OF buyurtmalar
FOR VALUES FROM ('2022-01-01') TO ('2023-01-01');
CREATE TABLE buyurtmalar_2023
PARTITION OF buyurtmalar
FOR VALUES FROM ('2023-01-01') TO ('2024-01-01');
CREATE TABLE buyurtmalar_2024
PARTITION OF buyurtmalar
FOR VALUES FROM ('2024-01-01') TO ('2025-01-01');
So'rov avvalgidek — ota jadvalga:
SELECT * FROM buyurtmalar WHERE sana >= '2024-01-01';
-- Faqat buyurtmalar_2024 skanlanadi — Partition Pruning
LIST Partitioning — qiymat ro'yxati bo'yicha
Mamlakat, mintaqa, kategoriya kabi aniq qiymatlar uchun:
CREATE TABLE buyurtmalar (
id BIGSERIAL,
mamlakat TEXT NOT NULL,
summa NUMERIC
) PARTITION BY LIST (mamlakat);
CREATE TABLE buyurtmalar_uz
PARTITION OF buyurtmalar FOR VALUES IN ('UZ', 'Uzbekistan');
CREATE TABLE buyurtmalar_kz
PARTITION OF buyurtmalar FOR VALUES IN ('KZ', 'Kazakhstan');
CREATE TABLE buyurtmalar_boshqa
PARTITION OF buyurtmalar DEFAULT; -- qolganlar uchun
HASH Partitioning — teng taqsimlash
Ma'lum partitsiya belgisi bo'lmasa — HASH bilan teng taqsimlash:
CREATE TABLE foydalanuvchilar (
id BIGSERIAL PRIMARY KEY,
ism TEXT
) PARTITION BY HASH (id);
CREATE TABLE foydalanuvchilar_0 PARTITION OF foydalanuvchilar
FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE foydalanuvchilar_1 PARTITION OF foydalanuvchilar
FOR VALUES WITH (MODULUS 4, REMAINDER 1);
CREATE TABLE foydalanuvchilar_2 PARTITION OF foydalanuvchilar
FOR VALUES WITH (MODULUS 4, REMAINDER 2);
CREATE TABLE foydalanuvchilar_3 PARTITION OF foydalanuvchilar
FOR VALUES WITH (MODULUS 4, REMAINDER 3);
4 ta bo'lak — ma'lumot teng taqsimlanadi.
Partition Pruning
PostgreSQL WHERE shartiga qarab kerakli bo'laklarni tanlab, boshqalarini o'tkazib yuboradi:
EXPLAIN SELECT * FROM buyurtmalar WHERE sana = '2024-06-15';
Append
-> Seq Scan on buyurtmalar_2024
Filter: (sana = '2024-06-15')
-- buyurtmalar_2022 va buyurtmalar_2023 umuman ko'rilmadi
Tez-tez uchraydigan xatolar
PRIMARY KEY partitsiya ustunini o'z ichiga olishi kerak:
-- ❌ — sana PRIMARY KEY da yo'q
CREATE TABLE buyurtmalar (
id BIGSERIAL PRIMARY KEY,
sana DATE
) PARTITION BY RANGE (sana);
-- ✅
PRIMARY KEY (id, sana) -- sana ham kiradi
Eski jadvalga partitioning qo'shish qiyin:
Mavjud katta jadvalni partitsiyalash — ma'lumotni qayta yozishni talab qiladi. Loyiha boshidan rejalashtirish kerak.
Xulosa
RANGE — sana, son oraliqlari (yillik, oylik bo'laklar)
LIST — aniq qiymatlar (mamlakat, kategoriya)
HASH — teng taqsimlash (aniq belgi yo'q)
Afzalliklar:
- Partition Pruning — faqat kerakli bo'lak skanlanadi
- Parallel query — bo'laklar parallel ishlanadi
- Eski ma'lumot — eski bo'lakni tez o'chirish (DROP PARTITION)
Keyingi dars
44-dars: Transaction — ACID, BEGIN, COMMIT, ROLLBACK, SAVEPOINT