Database Engineering

إتقان لقطات وتوقعات مصادر الأحداث في SQL

مصدر الأحداث هو نمط معماري قوي يعامل حالة التطبيق على أنها تسلسل للأحداث. بينما يوفر هذا مسار تدقيق غير قابل للتغيير وقدرات تشغيل قويّة، فإنه يطرح تحديًا كبيرًا في الأداء: إعادة بناء الحالة الحالية للكيان عن طريق إعادة تشغيل كل حدث فردي مكلفة حسابيًا ومكثفة في عمليات الإدخال/الإخراج (I/O). بالنسبة للمطورين من المستوى المتوسط إلى المتقدم الذين يبنون الأنظمة على قواعد البيانات العلائقية، تكمن الحل في استراتيجية قوية تتضمن اللقطات والتوقعات.

تحدي إعادة تشغيل الأحداث

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

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

تنفيذ اللقطات في قواعد البيانات العلائقية

بينما تُمدح مستودعات المستندات NoSQL غالبًا لمرونتها مع البيانات غير الطبيعية (denormalized)، يمكن لقواعد البيانات العلائقية التعامل مع اللقطات بفعالية من خلال بنية جدول بسيطة. المفتاح هو ربط اللقطة بمعرف الجذر التجميعي (Aggregate Root) وتتبع إصدارها.

إليك مثال عملي لكيفية هيكلة جدول اللقطات في SQL، مصمم للعمل جنبًا إلى جنب مع جدول الأحداث:

CREATE TABLE AggregateSnapshots (
    AggregateId UNIQUEIDENTIFIER NOT NULL,
    EventType VARCHAR(255) NOT NULL,
    SnapshotData NVARCHAR(MAX) NOT NULL,
    Version BIGINT NOT NULL,
    CreatedAt DATETIME2 NOT NULL DEFAULT GETUTCDATE(),
    CONSTRAINT PK_AggregateSnapshots PRIMARY KEY (AggregateId)
);

CREATE INDEX IX_AggregateSnapshots_Version 
ON AggregateSnapshots (AggregateId, Version DESC);

في هذا المخطط، يخزن SnapshotData الحالة المسلسلة للكيان (غالبًا بتنسيق JSON في إصدارات SQL Server أو PostgreSQL الحديثة). حقل Version حاسم؛ فهو يسمح لمنطق التطبيق بتحديد ما إذا كانت اللقطة أقدم من تدفق الأحداث الحالي وتحتاج إلى التحديث.

القفل المتفائل والاتساق

إحدى التعقيدات الدقيقة لتحديث اللقطات في قاعدة بيانات علائقية هي التعامل مع التزامن. لا يمكنك ببساطة الكتابة فوق لقطة، لأن ذلك سيؤدي إلى ظروف سباق حيث قد تفقد عمليات الكتابة المتزامنة البيانات. بدلاً من ذلك، يجب عليك استخدام القفل المتفائل (Optimistic Locking).

عند حفظ لقطة، يجب أن يتحقق رمز التطبيق الخاص بك مما إذا كان الإصدار الحالي في قاعدة البيانات يتطابق مع إصدار الحدث الذي أدى إلى حفظ اللقطة. إذا اختلفت الإصدارات، فقد قام عملية أخرى بتعديل الحالة، ويجب عليك إعادة المحاولة أو رفض العملية. يضمن هذا سلامة البيانات دون الحاجة إلى قفل معاملات ثقيل قد يؤدي إلى تدهور الأداء.

التوقعات: جانب القراءة في مصدر الأحداث

تحسن اللقطات جانب الكتابة وإعادة بناء حالة الكيان. ومع ذلك، فهي لا تساعد في الاستعلامات المعقدة للقراءة، مثل "أظهر لي جميع العملاء الذين أنفقوا أكثر من 1000 دولار في العام الماضي". لهذا الغرض، نحتاج إلى التوقعات.

التوقعات هي نماذج محسّنة للقراءة مشتقة من تدفق الأحداث. إنها تفصل نموذج الكتابة عن نموذج القراءة. في السياق العلائقي، يعني هذا غالبًا إنشاء جداول غير طبيعية يتم تحديثها بواسطة معالجات الأحداث (أو محرك توقعات منفصل) مع استمرار حفظ الأحداث الجديدة.

CREATE TABLE CustomerSpendingTotals (
    CustomerId UNIQUEIDENTIFIER PRIMARY KEY,
    TotalSpent DECIMAL(18, 2) DEFAULT 0.00,
    LastOrderDate DATETIME2,
    UpdatedVersion BIGINT
);

-- مثال على منطق معالج الأحداث (كود زائف)
public void Handle(OrderPlacedEvent @event) {
    // 1. تحديث منطق لقطة الكيان هنا...
    
    // 2. تحديث التوقع
    UPDATE CustomerSpendingTotals 
    SET TotalSpent = TotalSpent + @event.OrderValue,
        LastOrderDate = @event.OrderDate
    WHERE CustomerId = @event.CustomerId;

من خلال الحفاظ على هذه الجداول المتوقعة، يمكن لتطبيقك تقديم تقارير ولوحات معلومات معقدة مباشرة من SQL دون الحاجة إلى إعادة تشغيل تدفق الأحداث في كل طلب.

الخاتمة

يجمع الجمع بين مصدر الأحداث وقواعد البيانات العلائقية يتطلب نهجًا مدروسًا لتخزين البيانات. توفر اللقطات دفعة الأداء اللازمة لإعادة بناء حالة الكيان، بينما تتيح التوقعات استعلامات معقدة وفعالة. من خلال الاستفادة من قدرات JSON في SQL Server أو PostgreSQL وتنفيذ التحكم في التزامن المتفائل، يمكنك بناء أنظمة قابلة للتوسع وقابلة للصيانة تحافظ على فوائد مصدر الأحداث دون التضحية بأداء القراءة. مع نمو تطبيقك، تذكر أن فصل نماذج الكتابة والقراءة ليس مجرد خيار معماري، بل هو ضرورة للأداء طويل المدى.

Share: