Почему Нолок игнорируется «в предложении From, которая применима к целевой таблице обновления или оператора удаления»?

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

Вопрос

Я смущен фразой Бол:

«ReadUncommitted и NoLock не может быть указан для таблиц, измененных путем вставки, обновления или удаления операций. Оптимизатор запросов SQL Server игнорирует намеки на чтение и удаление NoLock в предложении FROM, который применяется к целевой таблице обновления или удаления оператора» [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 Hints» в предложении FROM, который применим к целевой таблице обновления или оператора удаления », потому что даже в 1) и 2) физическая таблица такая же, но логически таблица источника (в Select) и Target (в обновлении) Таблица разные.

Как написать заявление об обновлении, демонстрирующее, что с (nolock) игнорируется?
Почему это вообще следует игнорировать? Это игнорируется?
Или, если это неправильный вопрос, тогда
Почему синтаксис разрешает намек, который гарантированно игнорируется?

Еще раз, либо невозможно (или это?) Написать такое утверждение, как написано в документации, либо я не понимаю смысла «игнорировать» (в чем смысл игнорировать его? Или иметь его вообще?) ...

Обновление2:
Ответы показывают, что Нолок не (обновлен) игнорируется в операторе From of Update, что утверждается DOCS BOL [1].
Ну, суть этого вопроса:
Можете ли вы привести мне какой -либо пример (контекст), где игнорирование NoLock в Clace of Update Opport имело бы смысл?

[ 1 ]
Намеки на таблицу (Transact-SQL)
SQL Server 2008 R2
http://msdn.microsoft.com/en-us/library/ms187373.aspx

Это было полезно?

Решение

Отключение от обновления или оператора Delete не очевидно ни в одном из ваших примеров. У вас есть из -за пунктов в подразделениях, но это не то же самое.

Вот пункт об обновлении:

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 идентичные таблицы Test и TestDup [1], в одном сеансе (Windows of SSM) я выполняю

--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  

Таким образом, теперь это имеет смысл, но это противоречит документации, так как Нолок из пункта операции об обновлении не игнорируется, не так ли?

[ 1 ]
Создайте 2 идентично заполненные таблицы тест и тестирование:

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