انتقل إلى المحتوى الرئيسي
DevOpsMar 28, 2026

Deep EVM #25: تقسيم جداول PostgreSQL — عندما يتجاوز جدولك 10 مليون صف

OS
Open Soft Team

Engineering Team

متى تحتاج التقسيم

عندما يتجاوز جدول 10-100 مليون صف، تبدأ المشاكل:

  • الفهارس تنمو وتبطئ
  • VACUUM يستغرق وقتاً أطول
  • النسخ الاحتياطي يصبح بطيئاً
  • الاستعلامات تتدهور تدريجياً

التقسيم يحل هذا بتقسيم الجدول إلى أجزاء أصغر وأكثر قابلية للإدارة.

أنواع التقسيم

تقسيم بالنطاق (Range)

CREATE TABLE transactions (
    id UUID DEFAULT gen_random_uuid(),
    amount NUMERIC NOT NULL,
    created_at TIMESTAMPTZ NOT NULL
) PARTITION BY RANGE (created_at);

CREATE TABLE transactions_2024_01 PARTITION OF transactions
    FOR VALUES FROM ('2024-01-01') TO ('2024-02-01');
CREATE TABLE transactions_2024_02 PARTITION OF transactions
    FOR VALUES FROM ('2024-02-01') TO ('2024-03-01');

تقسيم بالقائمة (List)

CREATE TABLE articles (
    id UUID DEFAULT gen_random_uuid(),
    locale VARCHAR(5) NOT NULL,
    title TEXT NOT NULL
) PARTITION BY LIST (locale);

CREATE TABLE articles_en PARTITION OF articles FOR VALUES IN ('en');
CREATE TABLE articles_ar PARTITION OF articles FOR VALUES IN ('ar');
CREATE TABLE articles_ru PARTITION OF articles FOR VALUES IN ('ru');

تقسيم بالتجزئة (Hash)

CREATE TABLE events (
    id UUID DEFAULT gen_random_uuid(),
    user_id UUID NOT NULL,
    data JSONB
) PARTITION BY HASH (user_id);

CREATE TABLE events_0 PARTITION OF events FOR VALUES WITH (MODULUS 4, REMAINDER 0);
CREATE TABLE events_1 PARTITION OF events FOR VALUES WITH (MODULUS 4, REMAINDER 1);

الصيانة التلقائية

-- إنشاء أقسام مستقبلية تلقائياً
CREATE OR REPLACE FUNCTION create_monthly_partition()
RETURNS void AS $$
DECLARE
    next_month DATE := date_trunc('month', NOW() + interval '1 month');
    partition_name TEXT;
BEGIN
    partition_name := 'transactions_' || to_char(next_month, 'YYYY_MM');
    EXECUTE format(
        'CREATE TABLE IF NOT EXISTS %I PARTITION OF transactions FOR VALUES FROM (%L) TO (%L)',
        partition_name, next_month, next_month + interval '1 month'
    );
END;
$$ LANGUAGE plpgsql;

تأثير الأداء

العمليةبدون تقسيم (100M صف)مع تقسيم (12 قسم)
SELECT بتاريخ2,500ms50ms
INSERT5ms3ms
VACUUM45 دقيقة4 دقائق
حذف بيانات قديمة30 دقيقةفوري (DROP PARTITION)

الخلاصة

تقسيم الجداول ضروري عندما تنمو البيانات. اختر النوع المناسب: بالنطاق للبيانات الزمنية، بالقائمة للفئات، بالتجزئة للتوزيع المتساوي.