أساسيات ضبط أداء قاعدة بيانات MySQL
غالباً ما تكون قاعدة البيانات البطيئة هي السبب الأكثر شيوعاً وراء بطء التطبيق. وقبل أن ترفع مواصفات الخادم أو تعيد كتابة الشيفرة، فإن بضع ساعات من الضبط المنهجي لـ MySQL تستعيد عادةً معظم الأداء المفقود. يرشدك هذا الدليل عبر الأساسيات على خادم VPS أو خادم سحابي اعتيادي بنظام لينكس يشغّل MySQL 8.0: القياس، وضبط حجم الذاكرة، وقراءة خطط الاستعلام، وإضافة الفهارس المناسبة.
تنطبق هذه الخطوات على أي تثبيت قياسي لـ MySQL 8.0 — بما في ذلك قواعد البيانات المستضافة داخل المملكة على خادم VPS أو خادم سحابي من سكايلاين كلاود، حيث يساعد إبقاء بياناتك داخل المملكة العربية السعودية على الامتثال لنظام حماية البيانات الشخصية (PDPL) ومتطلبات الهيئة الوطنية للأمن السيبراني (NCA).
المتطلبات المسبقة
- خادم لينكس (Ubuntu 22.04/24.04 أو Debian أو عائلة RHEL) مثبّت عليه MySQL 8.0.
- مستخدم يملك صلاحية
sudoوحساب MySQL بصلاحيات إدارية. - حِمل عمل حقيقي أو تمثيلي — فالضبط على قاعدة بيانات خاملة لا يخبرك بشيء.
غيّر متغيراً واحداً في كل مرة ثم أعد القياس دائماً. الضبط دون قياس مجرد تخمين.
الخطوة الأولى — القياس أولاً عبر سجل الاستعلامات البطيئة
لا يمكنك ضبط ما لا تقيسه. يسجّل سجل الاستعلامات البطيئة كل عبارة تتجاوز عتبة زمنية محددة، وهو أسرع طريقة للعثور على أسوأ الاستعلامات لديك.
فعّله أثناء التشغيل (دون الحاجة لإعادة التشغيل):
SET GLOBAL slow_query_log = 'ON';
SET GLOBAL long_query_time = 1; -- سجّل الاستعلامات الأبطأ من ثانية واحدة
SET GLOBAL log_queries_not_using_indexes = 'ON';
ولجعله دائماً، أضف ما يلي إلى ملف إعدادات MySQL (/etc/mysql/mysql.conf.d/mysqld.cnf على Ubuntu/Debian، أو /etc/my.cnf على RHEL):
[mysqld]
slow_query_log = 1
slow_query_log_file = /var/log/mysql/mysql-slow.log
long_query_time = 1
log_queries_not_using_indexes = 1
اترك حِمل عمل تمثيلياً يعمل، ثم حلّل السجل. تقوم أداة pt-query-digest من حزمة Percona Toolkit بتجميع الاستعلامات المتطابقة حسب بصمتها وترتيبها بحسب إجمالي الوقت المستهلك:
sudo apt install percona-toolkit # على Debian/Ubuntu
pt-query-digest /var/log/mysql/mysql-slow.log | less
ركّز على الاستعلامات في أعلى التقرير — تلك ذات أعلى إجمالي زمن تنفيذ، وليس فقط أعلى زمن للتشغيل الواحد. فتحسين استعلام يعمل 10,000 مرة في الدقيقة أجدى من تحسين استعلام يعمل ليلاً مرة واحدة.
الخطوة الثانية — ضبط حجم InnoDB Buffer Pool
InnoDB هو محرك التخزين الافتراضي، ويقوم الـ buffer pool الخاص به بتخزين بيانات الجداول والفهارس في الذاكرة العشوائية (RAM). فإذا كانت مجموعة العمل لديك تتسع داخل الـ buffer pool، فإن MySQL يخدم معظم عمليات القراءة من الذاكرة بدل القرص — وهو عادةً أكبر مكسب منفرد.
تحقق من الحجم الحالي ونسبة الإصابة (hit ratio):
SHOW VARIABLES LIKE 'innodb_buffer_pool_size';
SELECT
(1 - (SELECT VARIABLE_VALUE FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_reads')
/ NULLIF((SELECT VARIABLE_VALUE FROM performance_schema.global_status
WHERE VARIABLE_NAME = 'Innodb_buffer_pool_read_requests'), 0)) * 100
AS hit_ratio_pct;
استهدف نسبة إصابة تبلغ 99% أو أعلى. ووفقاً لوثائق Oracle، اضبط الـ buffer pool على 50–75% من إجمالي الذاكرة العشوائية على خادم قاعدة بيانات مخصص، مع ترك مساحة لنظام التشغيل ولمخازن MySQL الأخرى (فـ InnoDB نفسه يحجز نحو 10% إضافية فوق الحجم المُعدّ). أما على خادم مشترك صغير، فابقَ أقرب إلى 50% واترك على الأقل 1–2 جيجابايت لنظام التشغيل.
بالنسبة لخادم مخصص بسعة 8 جيجابايت، يُعد نحو 5–6 جيجابايت نقطة انطلاق معقولة:
[mysqld]
innodb_buffer_pool_size = 5G
أعد تشغيل MySQL وأعد فحص نسبة الإصابة بعد أن يُحمّي حِمل العمل ذاكرة التخزين المؤقت. ولا تبالغ في الحجم: فإذا تجاوز الـ buffer pool مع بقية العمليات حجم الذاكرة العشوائية، فإن نظام التشغيل يلجأ إلى التبديل (swap) على القرص فينهار الأداء.
الخطوة الثالثة — قراءة خطط الاستعلام عبر EXPLAIN
بعد معرفة الاستعلامات البطيئة، اكتشف السبب. يُظهر الأمر EXPLAIN كيف ينوي MySQL تنفيذ العبارة:
EXPLAIN SELECT * FROM orders WHERE customer_id = 42 AND status = 'shipped';
أهم الأعمدة التي ينبغي مراقبتها:
| العمود | ما الذي تنتبه إليه |
|---|---|
type |
القيمة ALL تعني مسحاً كاملاً للجدول — وهي غالباً سيئة. يُفضّل ref أو range أو const. |
key |
الفهرس المستخدَم. القيمة NULL تعني عدم استخدام أي فهرس. |
rows |
العدد المقدّر للصفوف المفحوصة. الأقل أفضل. |
Extra |
تشير Using filesort أو Using temporary إلى خطوات فرز مكلفة. |
في MySQL 8.0 يمكنك المضي أبعد عبر EXPLAIN ANALYZE، الذي ينفّذ الاستعلام فعلياً ويُبلّغ بأزمنة حقيقية إلى جانب التقديرات:
EXPLAIN ANALYZE SELECT * FROM orders WHERE customer_id = 42 AND status = 'shipped';
هذه أكثر طريقة موثوقة للتأكد مما إذا كان تغيير الفهرس قد أفاد فعلاً.
الخطوة الرابعة — إضافة الفهارس المناسبة
المسح الكامل للجدول (type: ALL) على جدول كبير هو السبب الكلاسيكي للاستعلامات البطيئة. أضف فهرساً على الأعمدة المستخدمة في جُمل WHERE وJOIN وORDER BY.
بالنسبة للاستعلام أعلاه، يتيح فهرس مركّب يغطي العمودين المُرشَّحين لـ MySQL القفز مباشرةً إلى الصفوف المطابقة:
CREATE INDEX idx_orders_customer_status
ON orders (customer_id, status);
ترتيب الأعمدة مهم: ضع العمود الأكثر انتقائيةً — أو المستخدَم في مطابقات المساواة — أولاً. كما يخدم الفهرس المركّب الاستعلامات التي ترشّح على العمود القائد وحده (customer_id)، لذا نادراً ما تحتاج إلى فهرس منفصل أحادي العمود له.
أعد تشغيل EXPLAIN ANALYZE للتأكد من تحسّن type (مثلاً من ALL إلى ref) وأن قيمة rows انخفضت انخفاضاً حاداً.
الفهارس ليست مجانية — فهي تستهلك مساحة على القرص وتبطئ عمليات الكتابة (INSERT/UPDATE/DELETE)، إذ يجب صيانة كل فهرس. ففهرِس بتأنٍّ، وأزل الفهارس غير المستخدمة التي يمكنك التعرف عليها عبر عرض sys.schema_unused_indexes:
SELECT * FROM sys.schema_unused_indexes;
الخطوة الخامسة — التحقق ثم التكرار
الضبط حلقة متكررة وليس عملاً يُنجز مرة واحدة. بعد كل تغيير:
- أعد تشغيل الاستعلام المتأثر باستخدام
EXPLAIN ANALYZEوقارن الأزمنة. - اترك سجل الاستعلامات البطيئة يعمل مرة أخرى وأعد تحليله بأداة الـ digest.
- تأكد من أن نسبة إصابة الـ buffer pool ظلت مرتفعة.
تراجع عن أي تغيير لم يُفِد. واحتفظ بملاحظات عمّا غيّرته ولماذا — فأنت في المستقبل ستشكر نفسك في الحاضر.
أخطاء شائعة
- ضبط استعلام واحد بمعزل عن غيره. حسّن وفق الأثر الإجمالي (التكرار × التكلفة)، وهو ما يكشفه تحليل سجل الاستعلامات البطيئة.
- نسخ قيم
my.cnfمن المدونات. حجم الـ buffer pool يعتمد على ذاكرتك العشوائية ومجموعة بياناتك أنت. فقِس ولا تنسخ. - تغليف الأعمدة المفهرسة بدوال. فالعبارة
WHERE DATE(created_at) = '2026-06-08'لا تستطيع استخدام فهرس علىcreated_at؛ أعد كتابتها كنطاق:WHERE created_at >= '2026-06-08' AND created_at < '2026-06-09'. - استخدام
SELECT *على جداول عريضة. اجلب الأعمدة التي تحتاجها فقط كي يتمكن MySQL من استخدام الفهارس المُغطِّية (covering indexes).
الخلاصة
ضبط أداء MySQL عملٌ منهجي وليس سحراً: قِس عبر سجل الاستعلامات البطيئة، وامنح InnoDB ذاكرة عشوائية كافية، واقرأ خطط الاستعلام بـ EXPLAIN ANALYZE، وأضف الفهارس بتأنٍّ. هذه الأساسيات الأربعة تحل غالبية حالات البطء الواقعية قبل الحاجة إلى أي ترقية للأجهزة.
أما الأحمال التي تحتاج إلى توسّع أو زمن استجابة يمكن التنبؤ به أو دعم محلي بالعربية، فاستضف قواعد بياناتك داخل المملكة. استكشف خوادم VPS والخوادم السحابية من سكايلاين كلاود، واقرنها بـ استضافة البريد الإلكتروني للأعمال لمنظومة متكاملة، ثم أنشئ حسابك في سكايلاين كلاود لتنشر خادم MySQL مضبوطاً خلال دقائق.
Comments
0 total · 0 threads