كيف يمكنك قفل الجداول في SQL Server 2005، وهل يجب أن أفعل ذلك؟

StackOverflow https://stackoverflow.com/questions/57625

  •  09-06-2019
  •  | 
  •  

سؤال

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

--Grab the next message id
declare @MessageId uniqueidentifier
set @MessageId = (select top(1) ActionMessageId from UnacknowledgedDemands);

--Acknowledge the message
update ActionMessages
set AcknowledgedTime = getdate()
where ActionMessageId = @MessageId

--Select the entire message
...
...

في الكود أعلاه، ألا يمكن لإجراء مخزن آخر يعمل في نفس الوقت الحصول على نفس المعرف ومحاولة الاعتراف به في نفس الوقت؟هل يمكنني (أو ينبغي لي) تنفيذ نوع من القفل لمنع عملية مخزنة أخرى من التعرف على الرسائل التي يستعلم عنها عملية مخزنة أخرى؟

واو، هل كان لأي من هذا أي معنى؟من الصعب بعض الشيء أن نقول بالكلمات ...

هل كانت مفيدة؟

المحلول

شيء من هذا القبيل

--Grab the next message id
begin tran
declare @MessageId uniqueidentifier
select top 1 @MessageId =   ActionMessageId from UnacknowledgedDemands with(holdlock, updlock);

--Acknowledge the message
update ActionMessages
set AcknowledgedTime = getdate()
where ActionMessageId = @MessageId

-- some error checking
commit tran

--Select the entire message
...
...

نصائح أخرى

هذا يبدو وكأنه نوع من الوضع حيث OUTPUT يمكن أن تكون مفيدة:

-- Acknowledge and grab the next message
declare @message table (
    -- ...your `ActionMessages` columns here...
)
update ActionMessages
set    AcknowledgedTime = getdate()
output INSERTED.* into @message
where  ActionMessageId in (select top(1) ActionMessageId from UnacknowledgedDemands)
  and  AcknowledgedTime is null

-- Use the data in @message, which will have zero or one rows assuming
-- `ActionMessageId` uniquely identifies a row (strongly implied in your question)
...
...

هناك، نقوم بتحديث الصف والاستيلاء عليه في نفس العملية، والذي يخبر مُحسِّن الاستعلام بالضبط ما نقوم به، مما يسمح له باختيار القفل الأكثر دقة الذي يمكنه الاحتفاظ به لأقصر وقت ممكن.(على الرغم من أن بادئة العمود هي INSERTED, OUTPUT هو مثل المشغلات، معبرا عنها من حيث UPDATE يشبه حذف الصف وإدراج الصف الجديد.)

سأحتاج إلى مزيد من المعلومات حول الخاص بك ActionMessages و UnacknowledgedDemands الجداول (طرق العرض/TVFs/أيًا كان)، ناهيك عن معرفة أكبر بالقفل التلقائي لـ SQL Server، لتحديد ما إذا كان ذلك and AcknowledgedTime is null الشرط ضروري.إنه موجود للدفاع ضد حالة السباق بين التحديد الفرعي والتحديث.أنا متأكد من أنه لن يكون ضروريًا إذا كنا نختار من بينها ActionMessages نفسها (على سبيل المثال، where AcknowledgedTime is null مع top على ال update, ، بدلاً من الاختيار الفرعي تشغيل UnacknowledgedDemands).أتوقع أنه حتى لو كان غير ضروري، فهو غير ضار.

لاحظ أن OUTPUT موجود في SQL Server 2005 وما فوق.هذا هو ما قلت أنك تستخدمه، ولكن إذا كان التوافق مع عمليات تثبيت SQL Server 2000 القديمة مطلوبًا، فقد ترغب في اتباع طريقة أخرى.

@ كيلهوفر:

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

يحرر:بالإضافة إلى ذلك، لن يقوم SQL بالضرورة بقفل الجدول بأكمله - بل يمكنه فقط قفل الصفوف الضرورية.يرى هنا للحصول على نظرة عامة حول القفل في خادم SQL.

بدلاً من القفل الصريح، والذي غالبًا ما يتم تصعيده بواسطة SQL Server إلى دقة أعلى من المطلوب، لماذا لا تجرب هذا الأسلوب فقط:

declare @MessageId uniqueidentifier
select top 1 @MessageId = ActionMessageId from UnacknowledgedDemands

update ActionMessages
  set AcknowledgedTime = getdate()
  where ActionMessageId = @MessageId and AcknowledgedTime is null

if @@rowcount > 0
  /* acknoweldge succeeded */
else
  /* concurrent query acknowledged message before us,
     go back and try another one */

كلما قل قفلك - زاد التزامن لديك.

هل يجب عليك حقًا معالجة الأشياء واحدة تلو الأخرى؟ألا ينبغي أن يكون لديك SQL Server يقر بجميع الرسائل التي لم يتم الإقرار بها بتاريخ اليوم ويعيدها؟(كل ذلك أيضًا في معاملة بالطبع)

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

إذا كنت ترغب في تغليف التعليمات البرمجية الخاصة بك في معاملة، فسيقوم خادم SQL بالتعامل مع قفل الصفوف أو الجداول المناسبة.

begin transaction

--Grab the next message id
declare @MessageId uniqueidentifier
set @MessageId = (select top(1) ActionMessageId from UnacknowledgedDemands);

--Acknowledge the message
update ActionMessages
set AcknowledgedTime = getdate()
where ActionMessageId = @MessageId

commit transaction

--Select the entire message
...
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top