لماذا يتم تجاهل Nolock "في الفقرة من الفقرة التي تنطبق على الجدول المستهدف لتحديث أو حذف بيان"؟

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

سؤال

أنا في حيرة من أمري عبارة بول:

"لا يمكن تحديد ReadUncommitted و Nolock للجداول المعدلة عن طريق إدراج أو تحديث أو حذف العمليات. يتجاهل محسن استعلام SQL Server من التلميحات المخصصة و nolock في البند من الفقرة التي تنطبق على الجدول المستهدف لبيان التحديث أو الحذف" [1

على سبيل المثال ، إذا كتبت

--script 1) 
UPDATE Test SET Txt=(Select Txt from TEST WITH(NOLOCK) where ID=1) 
WHERE ID=1

يتم تشغيله بدون أخطاء (أو تحذيرات) وربما يعادل

--script 2)
set transaction isolation level SERIALIZABLE;
begin tran
Declare @nvarm nvarchar(max);

Select @nvarm=Txt from Test where ID=1;
--Select @nvarm;
UPDATE Test  SET Txt=@nvarm  WHERE ID=1;
commit;

الذي يتم تشغيله أيضًا بدون أخطاء أو تحذيرات.
هل هو مكافئ؟

الجدول هو نفسه ولكن من الناحية المنطقية الجدول المصدر وليس الجدول الهدف الذي يمكن أن أعيد كتابته 1) مع جدول مصدر مختلف كجدول آخر (مازي):

--script 3)
select *
into testDup
from TEST;

GO;

UPDATE Test SET Txt=(SELECT Txt FROM TestDUP WITH(NOLOCK) where ID=1) 
    WHERE ID=1

لماذا يجب تجاهل نولوك على طاولة أخرى؟
أو ، إذا كان خطأ ، فإن السؤال بعد ذلك
كيفية كتابة التحديث مع "تلميحات nolock في الفقرة من الفقرة التي تنطبق على الجدول المستهدف لتحديث أو حذف بيان" لأنه حتى في 1) (في التحديث) الجدول مختلف الجدول.

كيف تكتب بيان تحديث يوضح أنه مع (Nolock) يتم تجاهله؟
لماذا يجب تجاهله على الإطلاق؟ هل تم تجاهله؟
أو ، إذا كان سؤالًا خاطئًا ، إذن
لماذا يسمح بناء الجملة بالتلميح الذي يضمن تجاهله؟

مرة أخرى ، إما أنه من المستحيل (أم أنه؟) كتابة مثل هذا البيان كما هو مكتوب في الوثائق أو لا أفهم إحساس "يتجاهل" (ما هو المعنى لتجاهله؟ أو الحصول عليه على الإطلاق؟) ...

Update2:
تظهر الإجابات أن Nolock لم يتم تجاهله (محدث) في جملة من عبارة تحديث ما يتم تأكيده بواسطة مستندات BOL [1].
حسنًا ، جوهر هذا السؤال:
هل يمكن أن تعطيني أي مثال (سياق) حيث كان تجاهل Nolock في بند بيان التحديث أمرًا منطقيًا؟

[ 1 ]
تلميحات الجدول (Transact-SQL)
SQL Server 2008 R2
http://msdn.microsoft.com/en-us/library/ms187373.aspx

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

المحلول

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

إليك جملة من التحديث:

UPDATE t
SET Col = u.Val
FROM   /* <-- Start of FROM clause */
   Table t WITH (NOLOCK)
       inner join
   Table2 u
       on
          t.ID = u.ID
/* End of FROM clause */
WHERE
    u.Colx = 19

وكما تستدعي الوثائق ، WITH (NOLOCK) سيتم تجاهله في هذه الحالة. فيما يتعلق بالسبب المسموح به إذا تم تجاهله ، سيكون هناك تخمين واحد هو أن مثل هذا التلميح سيكون صالحًا في SELECT نسخة من استعلام "نفس" ، وكثيرا ما يقوم الناس بكتابة الاختيار (للتأكد من أنهم يستهدفون الصفوف/الأعمدة الصحيحة) ، ثم استبدال SELECT بند مع UPDATE/SET زوج من الجمل ، ويمكن أن يترك بقية الاستعلام دون تغيير.


تم تحديثه بناءً على التعليق/"الإجابة" من VGV8:

لا يزال تحديث المثال الخاص بك لا ينظر إليه جملة من بيان التحديث

ما يلي يعمل بشكل جيد ، حتى مع فتح Tablockx () على الاتصال الآخر:

UPDATE T  SET Txt= td.Txt
FROM TEST t inner join TESTDUP td  WITH (NOLOCK) on t.ID = td.ID
where t.ID = 1

نصائح أخرى

لا يوجد تخمين مطلوب.

يستخدم Sybase و MS SQL Server تأمينًا داخليًا وتلقائيًا للموارد 2PL ، ولكن مع الامتثال الكامل لمعيار ISO/IEC/ANSI SQL. يصبح بناء الجملة سخيفًا عندما تحاول فهم جميع المجموعات الممكنة ، لأن بعض الجمل ليست ذات صلة بكل أمر.

ما يحاول الدليل قوله ، لكنه لا يقول باللغة الإنجليزية البسيطة ، هو:

  • لأي عملية خارجية ، أو استعلام واحد داخل المعاملة ، يمكنك أداءك ، يمكنك ذلك SET ISOLATION LEVEL
  • يمكن تحديدها باستخدام UNCOMMITTED, NOLOCK, HOLDLOCKبناء الجملة كذلك
  • عندما يكون لديك IL واحد في الاستعلام الخارجي ، أو استعلام واحد داخل المعاملة ، ولكنك ترغب في استخدام IL مختلف للاستعلام الداخلي ، يمكن القيام به (استخدم المعدلات المختلفة على الاستعلام الداخلي)
  • لذلك يمكن أن يكون لديك معاملة تنفيذ في IL3 ، ولديك واحد SELECT داخلها تنفيذ في IL0 أو IL1

بشكل منفصل:

  • بغض النظر عما تعتقد أنك تفعله ، أو تريد القيام به ، لأن القفل تلقائي ، و ISOLATION LEVEL 3هو مطلوب إلى عن على UPDATES و DELETES, ، حيث READ UNCOMMITTED و NOLOCK لا تنطبق ، ولا يمكن استخدامها ، إذا كنت قد استخدمتها ، فسيتجاهلها الخادم

بعد إنشاء وملء 2 اختبار الجداول المتطابقة واختبار TestDup [1] ، في جلسة واحدة (Windows of SSMS) أقوم بتنفيذها

--2)
begin tran
Select Txt from TestDUP  with(TABLOCKX) 
WHERE ID=1
--rollback

تحدد الكتل من جلسة أخرى (نافذة SSMS) على نفس الجدول ، على سبيل المثال:

 --3.1)
select * from TestDUP

لكن لا

 --3.2)
select * from TestDUP WITH(NOLOCK)

لاحظ أن 3.1) محظور ولكن 3.2) ليس كذلك.

على الرغم من ذلك ، التحديث في اختبار جدول آخر باستخدام SELECT FROM TESTDUP

--4)WITH(NOLOCK) is not honored until completing
-- (commit/roollback)-ing transaction 2)
UPDATE Test  SET Txt=
(Select Txt from TESTDUP WITH(NOLOCK)  where ID=1)
  WHERE ID=1;

يتم حظره لأنه مع (Nolock) ، على جدول مصدر آخر ، يتم تجاهله من بند بيان التحديث.

تحديث:

--4.1)WITH(NOLOCK) is honored 
-- in FROM clause of UPDATE statement 
UPDATE Test  SET Txt= td.Txt
FROM TESTDUP td  WITH (NOLOCK)
where test.ID = 1 

--4.2) Note that without NOLOCK this script is blocked
-- until first transaction 2) completes (rollbacks or commits)
UPDATE Test  SET Txt= td.Txt
FROM TESTDUP td  WITH (NOLOCK)
where test.ID = 1  

لذا ، فمن المنطقي الآن ولكنه يتناقض مع الوثائق لأن Nolock في بند بيان التحديث لم يتم تجاهله ، أليس كذلك؟

[ 1 ]
قم بإنشاء 2 اختبار الجداول المملوءة واختبار TestDup:

if object_id('Test') IS not NULL
drop table Test;

CREATE TABLE Test (
  ID int IDENTITY PRIMARY KEY,
  Txt nvarchar(max) NOT NULL
)
GO
-----------
INSERT INTO Test
SELECT REPLICATE(CONVERT(nvarchar(max), 
     CHAR(65+ABS(CHECKSUM(NEWID()))%26)),100000)
GO 10

--COPYING TEST into TESTDUP with creating of the latter
select *
into testDup
from TEST;
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top