مشهدٌ يحيّر كثيرًا من المطوّرين: الموقع يتباطأ، الاستعلامات تأخذ ثوانٍ، والمستخدمون يشتكون — لكن حين تفتح لوحة الخادم تجد المعالج (CPU) لا يتجاوز 40 أو 60%. فإن لم يكن المعالج مشغولًا، فأين يضيع الوقت؟ الجواب هو جوهر Database Performance: قاعدة البيانات نادرًا ما تكون محدودة بالحساب؛ غالبًا تكون محدودة بالانتظار — انتظار القرص، أو قفل، أو استعلام سيّئ يقرأ ملايين الصفوف. في هذا الدليل نفكّك الأسباب الستّة الحقيقية للبطء — Disk Latency وIOPS والأقفال والفهارس والاستعلامات البطيئة وBuffer Pool — ونثبتها بتجربة حقيقية قِسناها على خادم مرام.

⚡ الإجابة المختصرة

غالبًا العنق ليس المعالج بل القرص (Disk I/O): بطء الاستعلامات ينتج عن Disk Latency عالٍ وIOPS محدود، أو أقفال (Locks)، أو فهارس ناقصة، أو Buffer Pool صغير يجبر القاعدة على القراءة من القرص باستمرار. الحل: قرص NVMe سريع، فهرسة صحيحة، وذاكرة كافية للتخزين المؤقت.

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

المعالج ينتظر، لا يحسب

مفتاح فهم Database Performance أنّ الاستعلام يمرّ بمراحل: تحليل، تخطيط، ثم جلب البيانات. المرحلة الأخيرة هي القاتلة — إن كانت البيانات في الذاكرة فالجلب فوريّ، وإن كانت على القرص فالمعالج يتوقّف وينتظر اكتمال القراءة. هذا الانتظار يظهر في مقياس اسمه iowait: نسبة الوقت الذي يقف فيه المعالج عاطلًا بانتظار الإدخال/الإخراج. فحين ترى CPU عند 50% وموقعك بطيء، انظر إلى iowait وزمن القرص قبل أن تلوم المعالج.

رحلة الاستعلام في Database Performance: الذاكرة سريعة والقرص بطيء
إن وُجدت البيانات في Buffer Pool = استجابة فورية؛ وإن غابت = قراءة قرص بطيئة والمعالج ينتظر

Disk Latency وIOPS: العنق الأول

أهمّ عاملين في أداء التخزين:

  • زمن القرص (Disk Latency): كم تستغرق عملية قراءة واحدة. على قرص بطيء قد تصل لأجزاء من المِلّي ثانية أو أكثر؛ اضربها بملايين القراءات وستفهم البطء.
  • IOPS: عدد عمليات الإدخال/الإخراج في الثانية التي يتحمّلها القرص. عند تجاوز الحدّ، تصطفّ الطلبات في طابور فيرتفع زمن الانتظار بينما يبقى المعالج خاملًا.

قاعدة البيانات تقوم بعددٍ هائل من القراءات العشوائية الصغيرة (4 كيلوبايت غالبًا)، وهي أصعب نمط على الأقراص. لذلك فإنّ قرصًا بزمن استجابة منخفض وIOPS عالٍ يصنع فارقًا مباشرًا في Database Performance — أكثر بكثير من ترقية المعالج.

💡 نصيحة: راقب iowait بأمر vmstat 1 أو mpstat. إن كان مرتفعًا مع بطء الاستعلامات، فالعنق هو القرص لا المعالج — والحلّ تخزينٌ أسرع أو كاش أكبر، لا معالج أقوى.

Buffer Pool: إثبات حقيقي من خادم مرام

Buffer Pool (أو shared_buffers في PostgreSQL) هو ذاكرة قاعدة البيانات المؤقتة حيث تحتفظ بالبيانات الساخنة. ما دامت بياناتك المتكرّرة تتّسع فيه، تُقرأ من الذاكرة بسرعة البرق. لكن حين تكبر البيانات عن الذاكرة، تُقرأ من القرص كل مرة — وهنا يظهر البطء. لنُثبت ذلك عمليًا:

نصبنا PostgreSQL على خادم مرام، وأنشأنا جدولًا بحجم 366 ميغابايت (أكبر من الذاكرة المؤقتة الافتراضية 128 ميغابايت)، ثم شغّلنا نفس الاستعلام مرّتين — مرّة والبيانات على القرص (بارد)، ومرّة وقد صارت في الكاش (دافئ):

إثبات حقيقي لأثر Buffer Pool والقرص على Database Performance من خادم مرام
نفس الاستعلام: 650ms من القرص مقابل 313ms من الذاكرة — والمعالج بقي خاملًا 37-75% أثناء البطء

🤝 من واقع مرام: النتيجة الحقيقية المقاسة: الاستعلام نفسه استغرق 650 مِلّي ثانية حين قرأ من القرص (46,784 قراءة قرص)، وانخفض إلى 313 مِلّي ثانية حين صارت البيانات في الكاش — أي أسرع ~2× دون تغيير سطر كود واحد. والأهمّ لإجابة سؤال المقال: أثناء الاستعلام البطيء بقي المعالج خاملًا بين 37% و75% مع ظهور iowait — أي أنه لم يقترب من 100%، بل كان ينتظر القرص. هذا هو الدليل الملموس: البطء لم يكن بسبب المعالج، بل بسبب الإدخال/الإخراج. القياس على PostgreSQL بأمر EXPLAIN (ANALYZE, BUFFERS).

-- شاهد بنفسك: أين يذهب الوقت؟ (PostgreSQL)
EXPLAIN (ANALYZE, BUFFERS)
SELECT count(*), avg(val) FROM big WHERE val > 500;

-- Buffers: shared read=46784   ← قراءات من القرص (بطيء)
-- Buffers: shared hit=...       ← قراءات من الذاكرة (سريع)
-- Execution Time: 649 ms  →  313 ms بعد التسخين

ملاحظة: الدرس: امنح قاعدة بياناتك ذاكرة كافية ليتّسع Buffer Pool لبياناتك الساخنة، وضع Redis أمامها للاستعلامات المتكرّرة. الذاكرة الوفيرة والقرص السريع أهمّ لقاعدة البيانات من عدد الأنوية.

الأقفال (Locks) والاستعلامات البطيئة

ليس كل بطء سببه القرص. هناك عاملان آخران لا يستهلكان معالجًا لكنهما يوقفان كل شيء:

  • الأقفال (Locks): حين تُعدّل معاملة صفًّا، تقفله حتى تنتهي، فتنتظر بقية المعاملات دورها. معاملة طويلة (مثلًا تحديث كبير داخل transaction مفتوح) تحبس عشرات الطلبات خلفها — والمعالج خاملٌ طوال انتظارها.
  • الاستعلامات البطيئة (Slow Queries): استعلام سيّئ التصميم — JOIN ثقيل، أو مشكلة N+1، أو جلب أعمدة لا تحتاجها — يجبر قاعدة البيانات على قراءة بيانات هائلة من القرص، فيتباطأ الجميع.

💡 نصيحة: فعّل سجلّ الاستعلامات البطيئة (slow query log) لرصد أثقل الاستعلامات، ثم حلّلها بـEXPLAIN لتعرف إن كانت تمسح الجدول كاملًا أو تستخدم فهرسًا. أطول 1% من الاستعلامات غالبًا سبب 90% من الشكاوى.

الفهارس (Indexes): أكبر مكسب منفرد

الفهرس (Index) هو بنية تسمح لقاعدة البيانات بإيجاد الصفوف دون مسح الجدول كاملًا — تمامًا كفهرس كتاب. بلا فهرس مناسب، يتحوّل استعلام بسيط إلى مسح تسلسلي يقرأ ملايين الصفوف من القرص. أضِف فهرسًا على العمود المستخدم في الشرط، فيهبط زمن الاستعلام من ثوانٍ إلى مِلّي ثوانٍ:

-- قبل: مسح كامل للجدول (بطيء، I/O عالٍ)
SELECT * FROM orders WHERE customer_id = 501;

-- الحل: فهرس على العمود المستخدم في البحث
CREATE INDEX idx_orders_customer ON orders (customer_id);

-- الآن يقفز الاستعلام مباشرة للصفوف المطلوبة

الفهرسة الصحيحة غالبًا هي أكبر تحسين منفرد لـDatabase Performance — وأرخص من أي ترقية عتاد. لكن لا تُفرط: كل فهرس يبطئ عمليات الكتابة قليلًا ويستهلك مساحة، فافهرس ما تبحث فيه فعلًا.

لماذا يهمّ Enterprise NVMe؟

بعد كل ما سبق، تتّضح الصورة: خمسةٌ من الأسباب الستّة تنتهي عند القرص. فحتى مع فهرسة ممتازة وذاكرة وفيرة، ستبقى هناك قراءات تفوت الذاكرة وتذهب للقرص — وسرعة القرص وقتها تحسم الأداء. هنا يفترق التخزين الاستهلاكي عن Enterprise NVMe:

  • زمن استجابة أدنى: أقراص المؤسسات تحافظ على زمن منخفض حتى تحت ضغط عالٍ متزامن، بينما ينهار الاستهلاكي.
  • IOPS ثابتة عالية: تتحمّل عشرات آلاف العمليات في الثانية دون تذبذب — بالضبط ما تحتاجه قاعدة البيانات.
  • حماية البيانات (PLP): حماية فقدان الطاقة وتحمّل كتابة (DWPD) أعلى بكثير — موثوقية لا تتوفّر في الاستهلاكي.

🤝 من واقع مرام: قِسنا زمن القرص على خادم الاختبار فبلغ ~0.07 مِلّي ثانية للعملية الواحدة. وتستخدم مرام في خوادمها أقراص Micron 9550 MAX (Enterprise NVMe من الجيل الخامس) التي قِسنا عليها ~118 ألف عملية قراءة عشوائية في الثانية (IOPS) بزمن منخفض ثابت. هذا الفارق لا يظهر في تصفّح بسيط، لكنه يصبح حاسمًا حين تتزاحم مئات الاستعلامات على قاعدة بيانات كبيرة — عندها يكون القرص السريع الفرقَ بين موقع سريع وموقع يختنق.

الخلاصة: قائمة تشخيص سريعة

حين تبطؤ قاعدة بياناتك والمعالج ليس 100%، لا تشترِ معالجًا أقوى فورًا — شخّص أولًا:

  • راقب iowait وvmstat: iowait مرتفع = العنق هو القرص.
  • افحص EXPLAIN (ANALYZE, BUFFERS): قراءات قرص كثيرة (read) = بياناتك لا تتّسع في الذاكرة.
  • راجع سجلّ الاستعلامات البطيئة وأضِف الفهارس الناقصة.
  • قصّر المعاملات لتقليل انتظار الأقفال.
  • زد الذاكرة ليتّسع Buffer Pool، وضع Redis أمام قاعدة البيانات.
  • تأكّد أن خادمك يستخدم تخزين Enterprise NVMe لا قرصًا مشتركًا بطيئًا.

Database Performance لعبة انتظار قبل أن تكون لعبة حساب. عالِج الانتظار — بالفهرسة والذاكرة والتخزين السريع — وستحصل على قفزة أداء تفوق بكثير ما يمنحه أي معالج أقوى.

لتعميق الموضوع: راجع تصميم قاعدة بيانات قابلة للتوسّع من Indexing إلى Sharding، وMySQL أم PostgreSQL لتطبيقك، ومقالنا عن Micron 9550 Enterprise NVMe مقابل NVMe التقليدي. وللمراجع: EXPLAIN في PostgreSQL، وInnoDB Buffer Pool، وsysbench.

قاعدة بياناتك تختنق على قرص بطيء؟ خوادم مرام بأقراص Enterprise NVMe (Micron 9550 MAX) وذاكرة وفيرة تمنح قاعدة بياناتك زمن استجابة منخفضًا وثباتًا تحت الضغط.

اطلب خادمًا بتخزين NVMe سريع