it-swarm.asia

إدارة التزامن عند استخدام نمط SELECT-UPDATE

لنفترض أن لديك الرمز التالي (يرجى تجاهل أنه فظيع):

BEGIN TRAN;
DECLARE @id int
SELECT @id = id + 1 FROM TableA;
UPDATE TableA SET id = @id; --TableA must have only one row, apparently!
COMMIT TRAN;
-- @id is returned to the client or used somewhere else

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

الآن ، ترك الرمز كما هو (أدرك أنه يتم التعامل مع هذا بشكل أفضل كبيان واحد أو حتى أفضل باستخدام عمود التعريفي/الهوية) ما هي الطرق المؤكدة للتعامل مع التزامن بشكل صحيح ومنع ظروف السباق التي تسمح لعميلين بالحصول على نفس الشيء قيمة الهوية؟

أنا متأكد تمامًا أن إضافة WITH (UPDLOCK, HOLDLOCK) إلى SELECT ستفي بالغرض. يبدو أن مستوى عزل المعاملات القابل للتسلسل يعمل أيضًا لأنه يمنع أي شخص آخر من قراءة ما قمت به حتى انتهاء عملية ( [~ # ~] تحديث [ ~ # ~] : هذا خطأ ، انظر إجابة مارتن). هل هذا صحيح؟ هل كلاهما يعملان بشكل جيد على قدم المساواة؟ هل يفضل أحدهما على الآخر؟

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

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

ملاحظة. لا ، لا أعرف أفضل إجابة وأريد حقًا الحصول على فهم أفضل! :)

25
ErikE

مجرد معالجة الجانب SERIALIZABLE مستوى العزل. نعم ، سيعمل هذا ولكن مع خطر الجمود.

سيتمكن كل من المعاملات من قراءة الصف في نفس الوقت. لن يقوموا بحظر بعضهم البعض لأنهم إما سيأخذون كائنًا S قفل أو فهرس RangeS-S أقفال تعتمد على هيكل الطاولة وهذه الأقفال متوافقة . لكنهم سيحظرون بعضهم البعض عند محاولة الحصول على الأقفال اللازمة للتحديث (الكائن IX القفل أو الفهرس RangeS-U على التوالي) مما سيؤدي إلى طريق مسدود.

إن استخدام تلميح UPDLOCK صريح بدلاً من ذلك سيؤدي إلى إجراء تسلسل للقراءات وبالتالي تجنب خطر الجمود.

11
Martin Smith

أعتقد أن أفضل نهج بالنسبة لك هو في الواقع تعريض الوحدة النمطية الخاصة بك إلى التزامن العالي وانظر بنفسك. في بعض الأحيان يكفي UPDLOCK وحده ، ولا توجد حاجة إلى HOLDLOCK. في بعض الأحيان يعمل sp_getapplock بشكل جيد للغاية. لن أدلي بأي بيان شامل هنا - أحيانًا تؤدي إضافة فهرس أو مشغل أو عرض مفهرس إلى تغيير النتيجة. نحن بحاجة إلى التأكيد على رمز الاختبار ونرى بأنفسنا على أساس كل حالة على حدة.

لقد كتبت عدة أمثلة على اختبار الإجهاد هنا

تحرير: لمعرفة أفضل للأجزاء الداخلية ، يمكنك قراءة كتب كالين ديلاني. ومع ذلك ، قد لا تتم مزامنة الكتب تمامًا مثل أي وثائق أخرى. إلى جانب ذلك ، هناك العديد من المجموعات التي يجب مراعاتها: ستة مستويات للعزل ، وأنواع عديدة من الأقفال ، وفهارس مجمعة/غير مجمعة ومن يدري ماذا أيضًا. هذا كثير من التوليفات. علاوة على ذلك ، يعد SQL Server مصدرًا مغلقًا ، لذلك لا يمكننا تنزيل شفرة المصدر وتصحيحها وما إلى ذلك - وهذا سيكون المصدر النهائي للمعرفة. قد يكون أي شيء آخر غير مكتمل أو قديم بعد الإصدار التالي أو حزمة الخدمة.

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

11
A-K

في هذه الحالة بالذات ، ستؤدي إضافة قفل UPDLOCK إلى SELECT إلى منع حدوث حالات شاذة. إن إضافة HOLDLOCK ليس ضروريًا حيث يتم تعليق قفل التحديث طوال مدة المعاملة ، لكنني أعترف بإدراجه بنفسي كعادة (ربما سيئة) في الماضي.

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

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

  • استرداد مستوى المخزون المترابط (<5 ، 10+ ، 50+ ، 100+) لمنتج في متجر ويب = قراءة متسخة (غير دقيق لا يهم).
  • التحقق من مستوى المخزون وتخفيضه على هذا المتجر الإلكتروني = قراءة قابلة للتكرار (يجب أن يكون لدينا المخزون قبل البيع ، يجب ألا ينتهي بنا الأمر مع مستوى مخزون سلبي).
  • نقل الأموال بين حسابي الجاري وحسابات التوفير في البنك = قابل للتسلسل (لا تخطئ في حساب أموالي أو تضيعها!).

تحرير: دفع تعليق @ AlexKuznetsov إلى إعادة قراءة السؤال وإزالة الخطأ الواضح جدًا في إجابتي. ملاحظة للذات على النشر في وقت متأخر من الليل.

9
Mark Storey-Smith