الحالة هي كما يلي:
عند استخدام إظهار حالة innodb للتحقق من حالة المحرك، تم اكتشاف مشكلة حالة توقف تام:
*** (1) المعاملة:
المعاملة 0 677833455، النشطة 0 ثانية، العملية رقم 11393، معرف مؤشر ترابط نظام التشغيل 278546 قراءة فهرس البداية
جداول MySQL قيد الاستخدام 1، مقفلة 1
LOCK WAIT 3 بنية (هياكل) القفل، حجم الكومة 320
معرف مؤشر ترابط MySQL 83، معرف الاستعلام 162348740 dcnet03 dcnet صفوف البحث عن تحديث
التحديث TSK_TASK قم بتعيين STATUS_ID = 1064، UPDATE_TIME = now () حيث STATUS_ID = 1061 وMON_TIME
*** (1) في انتظار منح هذا القفل:
معرف مساحة قفل السجل 0 الصفحة رقم 849384 n بت 208 فهرس `أساسي` للجدول `dcnet_db/TSK_TASK` معرف trx 0 677833455 lock_mode X يقفل التسجيل ولكن ليس فجوة انتظار
قفل السجل ، الكومة رقم 92 السجل المادي: n_fields 11؛ بتات المعلومات 0
0: len 8؛ asc b؛؛ 1: len 6؛ hex 00002866eaee؛ 0110; ;; 3: لين 8000000000050b2;; 4: لين 8; و ؛؛ 7: لين 23؛ 8616e642e706870; تصاعدي ن $؛
** * (2) المعاملة:
المعاملة 0 677833454، النشطة 0 ثانية، العملية رقم 11397، معرف مؤشر ترابط نظام التشغيل 344086 تحديث أو حذف، تم الإعلان عن الموضوع داخل
جداول InnoDB 499 mysql قيد الاستخدام 1، مقفل 1
3 بنية (هياكل) القفل، حجم الكومة 320، التراجع عن إدخالات السجل 1
معرف مؤشر ترابط MySQL 84، معرف الاستعلام 162348739 dcnet03 dcnet تحديث
التحديث TSK_TASK set STATUS_ID=1067,UPDATE_TIME=now () حيث المعرف في (9921180)
*** (2) يحمل القفل (الأقفال):
معرف مساحة تسجيل القفل 0 صفحة رقم 849384 بت 208 فهرس "أساسي" للجدول "dcnet_db/TSK_TASK" معرف trx 0 677833454 قفل_وضع X قفل
تسجيل ولكن ليس فجوة، كومة رقم 92 السجل المادي: n_fields 11؛ تنسيق معلومات مضغوط 0
0: len 8؛ ج ع ؛؛4: لين 8 ; 0; asc uploadfire.com/hand.php;; 8: لين 8;
8
؛
7833454
lock_mode X lock rec ولكن ليس فجوة في انتظار
القفل، الكومة رقم 395 السجل المادي: n_fields 3؛ تنسيق المعلومات المضغوط 0
0: len 8; 097629ج؛ تصاعدي ب ؛؛
*** نقوم بإرجاع المعاملات (1)
تتضمن مشكلة الجمود جدول TSK_TASK، والذي يُستخدم لحفظ مهام مراقبة النظام. فيما يلي الحقول والفهارس ذات الصلة:
المعرف: المفتاح الأساسي
MON_TIME: وقت المراقبة
؛ حالة المهمة
: KEY_TSKTASK_MONTIME2 (STATUS_ID، MON_TIME).
يوضح التحليل أن العبارتين المعنيتين لا ينبغي أن تتضمن نفس سجل TSK_TASK، فلماذا يتسبب ذلك في حالة توقف تام؟
بعد الاستعلام عن وثائق موقع MySQL الرسمي، وجدت أن هذا مرتبط بآلية فهرسة MySQL. يستخدم محرك InnoDB الخاص بـ MySQL الأقفال على مستوى الصف. كان فهمي الأصلي هو أن السجلات مقفلة مباشرةً، لكن هذا ليس هو الحال في الواقع.
النقاط الأساسية هي كما يلي:
بدلاً من قفل السجلات، يتم قفل الفهرس؛
أثناء عمليات التحديث والحذف، لا يقوم MySQL بقفل جميع سجلات الفهرس التي تم فحصها بواسطة شرط WHERE فحسب، بل يقوم أيضًا بقفل قيم المفاتيح المجاورة، ما يسمى بالمفتاح التالي. locking؛
على سبيل المثال، العبارة UPDATE TSK_TASK SET UPDATE_TIME = NOW() WHERE ID > 10000 ستقفل جميع السجلات بمفتاح أساسي أكبر من أو يساوي 1000. قبل اكتمال العبارة، لا يمكنك العمل على السجلات التي يكون مفتاحها الأساسي يساوي 1000. إلى 10000؛
عندما يكون الفهرس غير المجموعة (عند قفل سجل فهرس غير المجموعة، يجب أيضًا قفل سجل فهرس المجموعة ذي الصلة لإكمال العملية المقابلة.
تحليل جملتي SQL حيث حدثت المشكلة، ليس من الصعب العثور على المشكلة:
عند "تحديث TSK_TASK، قم بتعيين STATUS_ID=1064،UPDATE_TIME=now () حيث STATUS_ID=1061 وMON_TIME
بافتراض أن "تحديث مجموعة TSK_TASK STATUS_ID = 1067، UPDATE_TIME = now () حيث يتم تنفيذ المعرف في (9921180)" في وقت واحد تقريبًا، فإن هذا البيان يقوم أولاً بتأمين فهرس المجموعة (المفتاح الأساسي) نظرًا لأن قيمة STATUS_ID تحتاج إلى التحديث، فسيتم ذلك من الضروري أيضًا قفل جزء معين من KEY_TSKTASK_MONTIME2 في بعض سجلات الفهرس.
بهذه الطريقة، تقوم العبارة الأولى بتأمين سجل KEY_TSKTASK_MONTIME2 وتنتظر فهرس المفتاح الأساسي، بينما تقوم العبارة الثانية بتأمين سجل فهرس المفتاح الأساسي وتنتظر سجل KEY_TSKTASK_MONTIME2. في هذه الحالة، يحدث طريق مسدود.
قام المؤلف بحل مشكلة الجمود عن طريق تقسيم العبارة الأولى:
ابحث أولاً عن المعرف المؤهل: حدد المعرف من TSK_TASK حيث STATUS_ID=1061 وMON_TIME < date_sub(now(), INTERVAL 30 Minute); 1064 حيث المعرف في (....)
عند هذه النقطة، تم حل مشكلة الجمود بالكامل.