Get a quote

الحذف الناعم في PostgreSQL متعدد المستأجرين: الأنماط والمزالق

الحذف الناعم يبدو بسيطًا: أضف عمود deleted_at، وصفّ على NULL. لكن في قاعدة بيانات PostgreSQL متعددة المستأجرين على نطاق واسع، يخلق التطبيق الساذج انتفاخ الفهرس ومشاكل VACUUM وتسرب البيانات في استعلامات COUNT.

الحذف الناعم يبدو بسيطًا: أضف عمود deleted_at، وصفّ على IS NULL، وانتهى. لكن في قاعدة بيانات PostgreSQL متعددة المستأجرين على نطاق واسع، التطبيق الساذج يخلق انتفاخ الفهرس، ويكسر سياسات Row Level Security، ويسرب البيانات المحذوفة في استعلامات COUNT، ويحول تشغيل VACUUM من صيانة روتينية إلى تدخل طارئ.

لماذا يلجأ الفرق إلى الحذف الناعم؟

الحذف الناعم نمط لنزاهة البيانات. بدلًا من إزالة صف من قاعدة البيانات بـ DELETE، تضع طابع زمني (deleted_at = NOW()) وتصفيه في جميع الاستعلامات اللاحقة. الصف يبقى في قاعدة البيانات إلى الأبد، مما يعني أنك تحصل على تاريخ التدقيق مجانًا، ويمكنك استرداد السجلات المحذوفة عن طريق الخطأ دون استعادة نسخة احتياطية.

لمنتجات SaaS في لبنان ومنطقة الشرق الأوسط وشمال إفريقيا التي تخدم قطاعات ذات التزامات تنظيمية كالرعاية الصحية والخدمات القانونية والمالية، الحذف الناعم غالبًا ما يكون متطلبًا. منصة إدارة العيادات لا يمكنها السماح للطبيب بحذف سجل المريض بشكل دائم. نظام الفوترة القانوني لا يمكنه السماح للمشغل بمسح فاتورة.

ما هو التطبيق الساذج ولماذا يفشل على النطاق؟

النهج الساذج يبدو كالتالي:

ALTER TABLE orders ADD COLUMN deleted_at TIMESTAMPTZ;
CREATE INDEX orders_tenant_idx ON orders (tenant_id, created_at);

هذا يعمل بشكل جيد عند الحجم المنخفض. عند 500,000 صف لكل مستأجر، ينكسر بطريقتين:

أولًا، الفهرس orders_tenant_idx يشمل كل صف بما في ذلك المحذوفة. إذا كانت 30 بالمئة من صفوفك محذوفة ناعمًا، فإن فهرسك أكبر بنسبة 30 بالمئة مما يلزم للاستعلامات النشطة.

ثانيًا، deleted_at IS NULL ليس محمولًا بسيطًا للتساوي. PostgreSQL يمكنه استخدام فهرس B-tree للتصفية بـ tenant_id = $1، لكن الفحص IS NULL يجبره على مسح كل صف في قسم ذلك المستأجر من الفهرس.

كيف تستخدم الفهارس الجزئية لإصلاح هذا؟

الفهرس الجزئي يفهرس فقط الصفوف التي تطابق شرط WHERE. للحذف الناعم، النمط الصحيح هو:

CREATE INDEX orders_active_idx
    ON orders (tenant_id, created_at DESC)
    WHERE deleted_at IS NULL;

هذا الفهرس يحتوي فقط على الصفوف النشطة (غير المحذوفة). وهو أصغر بكثير من فهرس كامل على الجدول، ويمكن PostgreSQL استخدامه مباشرةً لنمط الاستعلام الشائع WHERE tenant_id = $1 AND deleted_at IS NULL.

كيف يتفاعل الحذف الناعم مع Row Level Security؟

في إعداد PostgreSQL متعدد المستأجرين، من المرجح أنك تستخدم Row Level Security لفرض عزل المستأجر. السياسة القياسية تبدو كالتالي:

ALTER TABLE orders ENABLE ROW LEVEL SECURITY;

CREATE POLICY orders_tenant_isolation ON orders
    USING (tenant_id = current_setting('app.tenant_id')::uuid);

هذه السياسة تعزل المستأجرين بشكل صحيح. لكنها لا تصفي الصفوف المحذوفة ناعمًا. لعزل أكثر صرامة، أضف مرشح الحذف الناعم إلى سياسة RLS:

CREATE POLICY orders_active_tenant ON orders
    USING (
        tenant_id = current_setting('app.tenant_id')::uuid
        AND deleted_at IS NULL
    );

نقوم بتنفيذ هذا عادةً مع دور قاعدة بيانات ثانٍ app_admin يتمتع بصلاحية مريحة لعمليات الاسترداد.

ما هي مشكلة انتفاخ الفهرس و VACUUM في الممارسة؟

PostgreSQL MVCC يعني أنه عند تشغيل UPDATE orders SET deleted_at = NOW() WHERE id = $1، الصف الأصلي لا يختفي. PostgreSQL يُنشئ إصدار صف جديد ويضع علامة على القديم كـ dead. VACUUM يستعيد المساحة من الصفوف الميتة.

في نظام SaaS بحجم حذف كبير، الحذف الناعم يُضاعف هذا. للجداول عالية التغيير، قم بتهيئة autovacuum بقوة:

ALTER TABLE orders SET (
    autovacuum_vacuum_scale_factor = 0.01,
    autovacuum_analyze_scale_factor = 0.005
);

لإحدى منصات التجارة الإلكترونية اللبنانية التي نعمل معها، كان هذا هو الفرق بين وقت استعلام p99 بمقدار 12ms و380ms على نقطة نهاية قائمة الطلبات. نفس حجم البيانات، نفس الفهارس، نفس الأجهزة. الفرق الوحيد كان تهيئة autovacuum.

الدروس الرئيسية من الإنتاج

الحذف الناعم هو النمط الصحيح لأنظمة SaaS حيث تحتاج البيانات إلى التدقيق والاسترداد. التطبيق الساذج يعمل على نطاق صغير وينكسر بشكل متوقع مع نمو البيانات. الفهارس الجزئية تقلل انتفاخ الفهرس بشكل كبير. تكامل RLS مع دور مدير منفصل يوفر عزلًا نظيفًا دون التضحية بقدرة الاسترداد.

هل تحتاج إلى مساعدة في البناء؟

فوكسير تبني واجهات خلفية SaaS متعددة المستأجرين على PostgreSQL للشركات في لبنان ومنطقة الشرق الأوسط وشمال إفريقيا. إذا كنت تصمم طبقة البيانات الخاصة بك وتريد تجنب المزالق الشائعة قبل أن تجعلها أحجام الجدول مكلفة الإصلاح، يمكننا المساعدة.

https://voxire.com/get-a-quote/

العودة إلى المدونة
Chat on WhatsApp