it-swarm.asia

ما هي الأسباب الرئيسية للجمود ، وهل يمكن منعها؟

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

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

لقد وجدت في وقت لاحق المطور الذي كتب قاعدة البيانات للنشر خاطئ. أضفت مفتاحًا أساسيًا وتم حل المشكلة.

شعرت بالسعادة وعدت إلى مشروعي ، وقمت ببعض الأبحاث لمعرفة سبب هذا الجمود ...

على ما يبدو ، كانت حالة انتظار دائرية هي سبب الجمود. يبدو أن التحديثات تستغرق وقتًا أطول بدون مفتاح أساسي مقارنةً بالمفتاح الأساسي.

أعلم أنها ليست نتيجة محددة جيدًا ، ولهذا السبب أنشرها هنا ...

  • هل المفتاح الأساسي المفقود هو المشكلة؟
  • هل هناك أي ظروف أخرى تؤدي إلى طريق مسدود بخلاف (الإقصاء المتبادل ، الانتظار والانتظار ، عدم الشفعة والانتظار الدائري)؟
  • كيف أمنع وتتبع الجمود؟
57
CoderHawk

تتبع الجمود هو أسهل من الاثنين:

بشكل افتراضي ، لا يتم كتابة الجمود في سجل الأخطاء. يمكنك أن تتسبب SQL في كتابة حالة توقف تام في سجل الأخطاء مع علامات التتبع 1204 و 3605.

كتابة معلومات حالة توقف تام في سجل أخطاء SQL Server: DBCC TRACEON (-1، 1204، 3605)

إيقاف تشغيله: DBCC TRACEOFF (-1، 1204، 3605)

راجع "استكشاف أخطاء Deadlocks" للحصول على مناقشة لعلامة التتبع 1204 والإخراج الذي ستحصل عليه عند تشغيله. https://msdn.Microsoft.com/en-us/library/ms178104.aspx

الوقاية أكثر صعوبة ، يجب عليك أن تتوخى الحذر في الأساس:

يقوم قالب التعليمات البرمجية 1 بتأمين المورد A ، ثم المورد B ، بهذا الترتيب.

يقوم Block Code 2 بتأمين المورد B ، ثم المورد A ، بهذا الترتيب.

هذه هي الحالة الكلاسيكية التي يمكن أن يحدث فيها حالة توقف تام ، إذا لم يكن قفل كلا الموارد غير ذري ، يمكن أن يقوم Block Code 1 بقفل A ويتم استبقائه ، ثم يقوم Block Block 2 بتأمين B قبل عودة A إلى وقت المعالجة. الآن لديك طريق مسدود.

لمنع هذا الشرط ، يمكنك فعل شيء مثل ما يلي

Code Code A (كود psuedo)

Lock Shared Resource Z
    Lock Resource A
    Lock Resource B
Unlock Shared Resource Z
...

Code Code B (رمز زائف)

Lock Shared Resource Z
    Lock Resource B
    Lock Resource A
Unlock Shared Resource Z
...

عدم نسيان فتح A و B عند الانتهاء منهما

هذا من شأنه أن يمنع الجمود بين كتلة التعليمات البرمجية A وكتلة التعليمات البرمجية B

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

39
BlackICE

مقالاتي المفضلة لقراءتها والتعرف على حالات الجمود هي: Simple Talk - Trackdown deadlocks and SQL Server Central - استخدام Profiler لحل حالات الجمود . سوف يعطونك عينات ونصائح حول كيفية التعامل مع هذا الوضع.

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

ولكن من الأفضل قراءة المقالات ، وستكون أجمل في النصائح.

24
Marian

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

على سبيل المثال ، في InnoDB :

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

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

...

أما بالنسبة لتتبعها ، فهذا يعتمد على برنامج قاعدة البيانات الذي تستخدمه.

16
Joe

فقط لتطوير شيء المؤشر. انها حقا سيئة حقا. يؤمن الجدول بأكمله ثم يعالج الصفوف واحدة تلو الأخرى.

من الأفضل أن تذهب من خلال الصفوف بطريقة المؤشر باستخدام حلقة من الوقت

في حلقة الوقت ، سيتم إجراء تحديد لكل صفوف في الحلقة وسيحدث القفل في صف واحد فقط في ذلك الوقت. بقية البيانات في الجدول مجانية للاستعلام ، وبالتالي تقليل فرص حدوث الجمود.

بالإضافة إلى أنه أسرع. يجعلك تتساءل لماذا هناك مؤشرات على أي حال.

فيما يلي مثال على هذا النوع من البنية:

DECLARE @LastID INT = (SELECT MAX(ID) FROM Tbl)
DECLARE @ID     INT = (SELECT MIN(ID) FROM Tbl)
WHILE @ID <= @LastID
    BEGIN
    IF EXISTS (SELECT * FROM Tbl WHERE ID = @ID)
        BEGIN
        -- Do something to this row of the table
        END

    SET @ID += 1  -- Don't forget this part!
    END

إذا كان حقل المعرف الخاص بك متناثرًا ، فقد ترغب في سحب قائمة منفصلة من المعرفات والتكرار من خلال ذلك:

DECLARE @IDs TABLE
    (
    Seq INT NOT NULL IDENTITY PRIMARY KEY,
    ID  INT NOT NULL
    )
INSERT INTO @IDs (ID)
    SELECT ID
    FROM Tbl
    WHERE 1=1  -- Criteria here

DECLARE @Rec     INT = 1
DECLARE @NumRecs INT = (SELECT MAX(Seq) FROM @IDs)
DECLARE @ID      INT
WHILE @Rec <= @NumRecs
    BEGIN
    SET @ID = (SELECT ID FROM @IDs WHERE Seq = @Seq)

    -- Do something to this row of the table

    SET @Seq += 1  -- Don't forget this part!
    END
7
Nicolas de Fontenay

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

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

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

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

6
Gerard ONeill