عبارات SQL Server SELECT تسبب الحظر
-
06-07-2019 - |
سؤال
نحن نستخدم قاعدة بيانات SQL Server 2005 (لا يوجد إصدار للصفوف) مع عبارة تحديد ضخمة، ونراها تمنع تشغيل العبارات الأخرى (يُرى باستخدام sp_who2
).لم أكن أدرك أن عبارات SELECT يمكن أن تسبب الحظر - هل هناك أي شيء يمكنني فعله للتخفيف من ذلك؟
المحلول
وSELECT يمكن منع التحديثات. وهناك نموذج بيانات مصممة بشكل صحيح والاستعلام يسبب سوى الحد الأدنى من الحجب ولا تكون قضية. و'المعتاد' WITH تلميح NOLOCK هو دائما تقريبا إجابة خاطئة. الإجابة الصحيحة هي أن يوفق الاستعلام الخاص بك حتى لا تتفحص الجداول ضخمة.
إذا كان الاستعلام untunable ثم عليك أن تنظر أولا لقطة مستوى العزل أ > والثاني يجب عليك أن تنظر استخدام لقطات DATABASE وينبغي أن يكون الخيار الأخير القذرة يقرأ (وهو أفضل لتغيير مستوى العزل بدلا من استخدام تلميح NOLOCK). لاحظ أن القذرة يقرأ، كما ينص على اسم واضح، سيعود بيانات غير متناسقة (على سبيل المثال قد يكون إجمالي الميزانية الخاصة بك غير متوازن).
نصائح أخرى
من توثيق:
Shared (S)
تسمح الأقفال بقراءة المعاملات المتزامنة(SELECT)
مورد تحت سيطرة التزامن المتشائم.لمزيد من المعلومات، راجعTypes of Concurrency Control
.لا يمكن لأي معاملات أخرى تعديل البيانات أثناء ذلكshared (S)
الأقفال موجودة على المورد.Shared (S)
يتم تحرير الأقفال الموجودة على المورد بمجرد اكتمال عملية القراءة، ما لم يتم تعيين مستوى عزل المعاملة على قراءة قابلة للتكرار أو أعلى، أو يتم استخدام تلميح القفل للاحتفاظ بالأقفال الموجودة على المورد.shared (S)
أقفال طوال مدة الصفقة.
أ shared lock
متوافق مع قفل مشترك آخر أو قفل تحديث، ولكن ليس مع قفل حصري.
وهذا يعني أن الخاص بك SELECT
سيتم حظر الاستعلامات UPDATE
و INSERT
الاستعلامات والعكس.
أ SELECT
سيضع الاستعلام قفلًا مشتركًا مؤقتًا عندما يقرأ كتلة من القيم من الجدول، ويزيله عند الانتهاء من القراءة.
أثناء وجود القفل، لن تتمكن من فعل أي شيء بالبيانات الموجودة في المنطقة المقفلة.
اثنين SELECT
لن تحظر الاستعلامات بعضها البعض أبدًا (ما لم تكن كذلك SELECT FOR UPDATE
)
يمكنك تمكين SNAPSHOT
مستوى العزل على قاعدة البيانات الخاصة بك واستخدامها، ولكن لاحظ أنه لن يمنع UPDATE
الاستعلامات من أن تكون مقفلة SELECT
الاستعلامات (التي يبدو أنها حالتك).
ومع ذلك، فإنه سوف يمنع SELECT
الاستعلامات من أن تكون مقفلة UPDATE
.
لاحظ ذلك أيضًا SQL Server
, على عكس Oracle
, ، يستخدم مدير القفل ويبقيه مقفلاً في قائمة مرتبطة بالذاكرة.
وهذا يعني أنه في ظل التحميل الثقيل، فإن مجرد وضع القفل وإزالته قد يكون بطيئًا، حيث يجب أن تكون القائمة المرتبطة نفسها مقفلة بواسطة سلسلة المعاملات.
لأداء القذرة يمكنك إما:
using (new TransactionScope(TransactionScopeOption.Required,
new TransactionOptions {
IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted }))
{
//Your code here
}
أو
SelectCommand = "SELECT * FROM Table1 WITH (NOLOCK) INNER JOIN Table2 WITH (NOLOCK) ..."
وتذكر أن عليك أن تكتب مع (NOLOCK) بعد كل الجدول الذي تريد قراءة القذرة
هل يمكن تعيين مستوى المعاملة قراءة غير ملتزم
هل يمكن أيضا الحصول على المآزق:
و"المآزق التي تنطوي على جدول واحد فقط" HTTP: // sqlblog.com/blogs/alexander_kuznetsov/archive/2009/01/01/reproducing-deadlocks-involving-only-one-table.aspx
ووأو نتائج غير صحيحة:
و"تختار تحت READ المرتكبة وREAD تكرار قد ترجع نتائج غير صحيحة."
<وأ href = "http://www2.sqlblog.com/blogs/alexander_kuznetsov/archive/2009/04/10/selects-under-read-committed-and-repeatable-read-may-return-incorrect- results.aspx "يختلط =" نوفولو noreferrer "> http://www2.sqlblog.com/blogs/alexander_kuznetsov/archive/2009/04/10/selects-under-read-committed-and-repeatable-read-may-return -incorrect-results.aspx
ويمكنك استخدام WITH(READPAST)
الجدول التلميح. انها مختلفة من WITH(NOLOCK)
. وسوف تحصل على البيانات قبل بدأ العملية ولن تمنع أي شخص. تخيل ذلك، قمت بتشغيل بيان قبل بدأ العملية.
SELECT * FROM table1 WITH (READPAST)