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

استعلامات التحليلات والتقارير تشغّل لوحات BI، رسائل KPI الأسبوعية، مراجعات «كيف كنا في الربع الماضي؟»، وأسئلة استكشافية مثل «أي قناة تسويقية حققت أعلى قيمة مدى الحياة في ألمانيا؟» عادةً ما تكون قراءة بكثافة وتركز على تلخيص الكثير من البيانات التاريخية.
بدلًا من جلب سجل عميل واحد، غالبًا ما تقوم استعلامات التحليلات بـ:
هناك أمران يجعلان التحليلات صعبة على محرك قاعدة بيانات تقليدي:
المسوح الكبيرة مكلفة. قراءة الكثير من الصفوف تعني نشاطًا كبيرًا في القرص والذاكرة، حتى لو كانت النتيجة النهائية ضئيلة.
التزامن حقيقي. لوحة البيانات ليست "استعلامًا واحدًا"؛ إنها العديد من المخططات التي تُحمل معًا، مضروبة بعدد المستخدمين، بالإضافة إلى تقارير مجدولة واستعلامات استكشافية تعمل بالتوازي.
تهدف الأنظمة الموجهة للأعمدة إلى جعل المسوح والتجمعات سريعة ومتوقَّعة—غالبًا بتكلفة أقل لكل استعلام—مع دعم تزامن مرتفع للوحات التحكم.
الحداثة بعدٌ منفصل. كثير من إعدادات التحليلات تتاجر بتحديثات دون ثانية لصالح تقارير أسرع عن طريق تحميل البيانات على دفعات (كل بضع دقائق أو كل ساعة). بعض المنصات تدعم الإدخال شبه في الوقت الحقيقي، لكن التحديثات والحذف قد تظل أكثر تعقيدًا من الأنظمة المعاملاتية.
قواعد البيانات الموجهة للأعمدة مبنية أساسًا لأعمال نمط OLAP.
أسهل طريقة لفهم قاعدة بيانات موجهة للأعمدة هي تصور كيف يُنظم الجدول على القرص.
تخيّل جدول orders:
| order_id | customer_id | order_date | status | total |
|---|---|---|---|---|
| 1001 | 77 | 2025-01-03 | shipped | 120.50 |
| 1002 | 12 | 2025-01-03 | pending | 35.00 |
| 1003 | 77 | 2025-01-04 | shipped | 89.99 |
في مخزن الصفوف، تُحفظ قيم نفس الصف بجوار بعضها. مفهوميًا يشبه:
هذا مثالي عندما يحتاج تطبيقك غالبًا إلى سجلات كاملة (مثلاً، "جلب الطلب 1002 وتحديث حالته").
في مخزن الأعمدة، تُخزن قيم نفس العمود معًا:
order_id: 1001, 1002, 1003, …status: shipped, pending, shipped, …total: 120.50, 35.00, 89.99, …غالبًا ما تلمس استعلامات التحليلات أعمدة قليلة ولكن على صفوف كثيرة. على سبيل المثال:
SUM(total) حسب اليومAVG(total) حسب العميلGROUP BY status لعد الطلباتمع التخزين العمودي، يمكن لاستعلام مثل "إجمالي الإيرادات يوميًا" قراءة order_date وtotal فقط، بدلًا من تحميل customer_id وstatus إلى الذاكرة لكل صف. بيانات أقل مقروءة تعني مسوح أسرع—وهذه هي الميزة الأساسية التي تبني عليها مخازن الأعمدة.
التخزين العمودي سريع للتحليلات لأن معظم التقارير لا تحتاج لمعظم بياناتك. إذا استخدم الاستعلام بضعة حقول فقط، يمكن لقاعدة بيانات موجهة للأعمدة قراءة تلك الأعمدة فقط من القرص—بدلاً من جلب الصفوف بأكملها.
غالبًا ما يكون أداء المسح محددًا بسرعة نقل البايتات من التخزين إلى الذاكرة (ثم عبر المعالج). يخسر مخزن الصفوف في العادة لأنه يقرأ صفوفًا كاملة، فتَحمِل قيمًا "زائدة" لم تُطلَب.
مع التخزين العمودي، يعيش كل عمود في منطقة متجاورة مستمرة. لذا استعلام مثل "إجمالي الإيرادات حسب اليوم" قد يقرأ فقط:
كل شيء آخر (الأسماء، العناوين، الملاحظات، عشرات السمات نادرة الاستخدام) يبقى على القرص.
تميل جداول التحليلات لأن تتّسع مع الوقت: سمات منتجات جديدة، علامات تسويقية، أعلام تشغيلية، وحقول "للاحتياط". ومع ذلك، عادةً ما تلمس التقارير مجموعة صغيرة—غالبًا 5–20 عمودًا من أصل 100+. التخزين العمودي يتماشى مع هذه الحقيقة ويتجنّب سحب أعمدة غير مستخدمة تجعل مسح الجداول العريضة مكلفًا.
"اقتطاع الأعمدة" يعني فقط أن قاعدة البيانات تتخطى الأعمدة التي لا يشير إليها الاستعلام. هذا يقلل:
والنتيجة مسوح أسرع، خصوصًا على مجموعات بيانات كبيرة حيث تكلفة قراءة بيانات غير ضرورية تهيمن على زمن الاستعلام.
الضغط هو واحد من القوى الصامتة لقواعد البيانات الموجهة للأعمدة. عندما تُخزن البيانات عموديًا، يميل كل عمود إلى احتواء نوع متشابه من القيم (تواريخ مع تواريخ، دول مع دول، رموز حالة مع رموز حالة). القيم المتشابهة تُضغط جيدًا—غالبًا أفضل بكثير من نفس البيانات مخزّنة صفًّا بعد صف حيث تجاور الحقول غير المرتبطة بعضها البعض.
تخيّل عمود order_status يحتوي غالبًا على "shipped" أو "processing" أو "returned" مكررة ملايين المرات. أو عمود طابع زمني تزداد قيمه تدريجيًا. في مخزن الأعمدة، تُجمَع هذه الأنماط التكرارية أو المتوقعة، فيُمكن تمثيلها بعدد أقل من البتات.
تدمج معظم محركات التحليلات تقنيات متعددة، على سبيل المثال:
البيانات الأصغر تعني بايتات أقل تُسحب من القرص أو التخزين الكائني، وبيانات أقل تتحرك عبر الذاكرة وكاش المعالج. لاستعلامات التقارير التي تمسح الكثير من الصفوف لكن أعمدة قليلة، يمكن للضغط تقليل I/O بشكل كبير—غالبًا الجزء الأبطأ في التحليلات.
ميزة إضافية: العديد من الأنظمة يمكنها العمل على البيانات المضغوطة بكفاءة (أو فك الضغط على دفعات كبيرة)، مما يحافظ على إنتاجية عالية أثناء تنفيذ تجمعات مثل sum، count، وgroup-by.
الضغط ليس مجانيًا. تنفق قاعدة البيانات دورات CPU لضغط البيانات أثناء الإدخال وفك الضغط أثناء تنفيذ الاستعلام. في الممارسة، تفوز أحمال التحليلات غالبًا لأن وفورات I/O تفوق تكلفة CPU الإضافية—لكن بالنسبة لاستعلامات محدودة بالمعالج أو بيانات فائقة الحداثة، قد يتغيّر التوازن.
التخزين العمودي يساعدك على قراءة بايتات أقل. المعالجة المتجهة تساعدك على الحساب بشكل أسرع بعد وصول تلك البايتات إلى الذاكرة.
محركات تقليدية تقيم الاستعلام صفًّا بعد صف: تحميل صف، التحقق من شرط، تحديث تجمع، الانتقال للصف التالي. هذا يخلق الكثير من العمليات الصغيرة وتفرعات دائمة، ما يجعل المعالج مشغولًا بالعبء الزائد بدلًا من العمل الحقيقي.
التنفيذ المتجه يقلب النموذج: يعالج المحرك القيم في دفعات (غالبًا آلاف القيم من عمود واحد دفعةً واحدة). بدلًا من استدعاء نفس المنطق لكل صف، يشغّل المحرك حلقات ضيقة على مصفوفات القيم.
المعالجة على دفعات تُحسّن كفاءة CPU لأن:
تخيل: "إجمالي الإيرادات من الطلبات في 2025 للفئة = 'Books'".
يمكن لمحرك متجه أن:
category وينشئ قناعًا بولينيًا حيث تساوي الفئة "Books".order_date ويوسّع القناع للاحتفاظ فقط بعام 2025.revenue ويجمعها باستخدام القناع—غالبًا باستخدام SIMD لجمع عدة أرقام في دورة معالج واحدة.نظرًا لأنه يعمل على أعمدة ودفعات، يتجنّب المحرك لمس الحقول غير المرتبطة ويتجنب عبء المعالجة لكل صف، وهو سبب رئيسي لتفوّق مخازن الأعمدة على أحمال التحليلات.
غالبًا ما تلمس استعلامات التحليلات عددًا كبيرًا من الصفوف: "عرض الإيرادات شهريًا"، "عدّ الأحداث حسب الدولة"، "إيجاد أفضل 100 منتج". في أنظمة OLTP، الفهارس هي الأداة الأساسية لأن الاستعلامات عادةً تسترجع عددًا قليلًا من الصفوف (بالمفتاح الأساسي، البريد الإلكتروني، رقم الطلب). للتحليلات، بناء وصيانة فهارس كثيرة يمكن أن يكون مكلفًا، وكثير من الاستعلامات لا تزال بحاجة لمسح أجزاء كبيرة من البيانات—لذلك تركز مخازن الأعمدة على جعل المسوح ذكية وسريعة.
تتبع العديد من قواعد البيانات الموجهة للأعمدة بيانات وصفية بسيطة لكل كتلة بيانات (تُدعَى "stripe" أو "row group" أو "segment")، مثل القيمة الدنيا والقصوى في ذلك البلوك.
إذا كان استعلامك يفلتر amount > 100، وكان وصف البلوك يظهر max(amount) = 80، يمكن للمحرك تخطي قراءة ذلك البلوك بالكامل لعمود amount—بدون الرجوع إلى فهرس تقليدي. هذه الخرائط رخيصة للتخزين وسريعة للتحقّق وتعمل جيدًا مع الأعمدة التي تُرتب طبيعيًا.
التقسيم يقسم الجدول إلى أجزاء منفصلة، غالبًا حسب التاريخ. افترض أن الأحداث مقسّمة حسب اليوم وطلب التقرير يشمل WHERE event_date BETWEEN '2025-10-01' AND '2025-10-31'. يمكن لقاعدة البيانات تجاهل كل الأقسام خارج أكتوبر ومسح الأقسام ذات الصلة فقط.
هذا يمكن أن يقلل I/O بشكل كبير لأنك لا تتخطى بلوكات فقط—بل تتخطى ملفات أو أجزاء فيزيائية كبيرة من الجدول.
إذا كانت البيانات مرتبة (أو "مجمّعة") بمفاتيح فلترة شائعة—مثل event_date، customer_id، أو country—فإن القيم المتطابقة تميل إلى التجمّع معًا. هذا يحسّن فعالية كل من تقليم الأقسام وخرائط المناطق، لأن البلوكات غير المطابقة تفشل بسرعة في فحوص الحدّ الأدنى/الحدّ الأقصى وتُتخطى.
الاستعلامات التحليلية والتقريرية هي استفسارات قراءة كثيفة تلخّص كميات كبيرة من البيانات التاريخية—مثل الإيرادات حسب الشهر، التحويلات حسب الحملة، أو الاحتفاظ حسب الفِرق. عادةً ما تمسح صفوفًا كثيرة، تستخدم مجموعة فرعية من الأعمدة، تحسب تجمعات، وتُرجِع مجموعة نتائج صغيرة لعرضها في مخططات أو جداول.
تضغط هذه الأحمال على قواعد البيانات أساسًا لأن:
يمكن لمحركات OLTP المعتمدة على الصفوف تنفيذ ذلك، لكن التكلفة والزمن يصبحان غالبًا غير متوقعين على نطاق واسع.
في مخزن الصفوف، قيم نفس الصف تكون بجوار بعضها على القرص، وهذا ممتاز لجلب أو تحديث سجل واحد. في مخزن الأعمدة، قيم نفس العمود تكون مجمعة معًا، وهذا ممتاز عندما يقرأ الاستعلام أعمدة قليلة عبر صفوف كثيرة.
إذا كان التقرير يحتاج فقط order_date وtotal، يمكن لمخزن الأعمدة تجنّب قراءة أعمدة غير ذات صلة مثل status أو customer_id.
لأن معظم استعلامات التحليلات تقرأ مجموعة صغيرة من الأعمدة فقط. تستطيع مخازن الأعمدة تطبيق اقتطاع الأعمدة (column pruning) لتخطي الأعمدة غير المستخدمة، لذا تقرأ عددًا أقل من البايتات.
قراءة أقل تعني عادةً:
تنظيم الأعمدة يجمع قيمًا متشابهة معًا (تواريخ مع تواريخ، دول مع دول)، فتضغط جيدًا.
أنماط شائعة:
الضغط يقلل التخزين ويُسرّع عمليات المسح بتقليل I/O، مع وجود تكلفة CPU لضغط/فك الضغط.
التنفيذ المتجه (vectorized) يعالج البيانات في دفعات (مصفوفات قيم) بدلًا من صفًّا بعد صف. هذا مفيد لأن:
لهذا السبب تُبقى مخازن الأعمدة سريعة حتى عند مسح نطاقات كبيرة من البيانات.
تخزن المحركات عادةً بيانات وصفية خفيفة لكل بلوك بيانات (مثل الحدّ الأدنى والحدّ الأقصى). إذا كان فلتر الاستعلام لا يمكن أن يطابق بلوكًا معينًا (مثلاً max(amount) < 100 مقابل شرط amount > 100)، يمكن للمحرك تخطي قراءة ذلك البلوك كله.
هذا يعمل جيدًا عند الجمع مع:
يظهر التوازي بطريقتين:
نمط “تقسيم ثم دمج” (split-and-merge) يجعل عمليات التجميع والمجموعات قابلة للتوسع دون نقل صفوف خام بكثافة عبر الشبكة.
التحديثات ذات الصف الواحد أصعب لأن "الصف" موزّع فعليًا عبر ملفات/مقاطع أعمدة متعددة ومضغوط. تغيير قيمة واحدة قد يضطر لإعادة كتابة بلوكات أكبر.
الاستراتيجيات الشائعة:
لهذا كثير من الأنظمة تقبل تأخير بسيط في التحديثات (قرب الوقت الحقيقي، مثل 1–5 دقائق) بدلًا من رؤية فورية.
اختبر باستخدام بيانات واستعلامات شبيهة للإنتاج:
إجراء PoC صغير مع 10–20 استعلامًا حقيقيًا يكشف عادةً أكثر من مقارنات البائعين الاصطناعية.