Warum NOLOCK wird ignoriert „in der FROM-Klausel, die in die Zieltabelle einer UPDATE oder DELETE-Anweisung anwenden“?
-
29-09-2019 - |
Frage
Ich bin von der BOL Satz verwirrt:
„READUNCOMMITTED und NOLOCK nicht für Tabellen einfügen, aktualisieren oder Löschvorgänge geändert angegeben werden. Der SQL-Server-Abfrageoptimierer ignoriert die READUNCOMMITTED und NOLOCK Hinweise in der FROM-Klausel, die in die Zieltabelle einer UPDATE oder DELETE-Anweisung anwenden“ [1]
Zum Beispiel, wenn ich schreibe
--script 1)
UPDATE Test SET Txt=(Select Txt from TEST WITH(NOLOCK) where ID=1)
WHERE ID=1
wird es ohne Fehler (oder Warnungen) laufen und ist wahrscheinlich äquivalent zu
--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;
, die auch ohne Fehler oder Warnungen ausgeführt wird.
Ist es gleichwertig?
In der Tabelle ist das gleiche, aber in FROM ist es logisch die Quelltabelle nicht die Zieltabelle Ich könnte neu geschrieben 1) mit einer anderen Quelltabelle als ein anderen (physische) Tabelle habe:
--script 3)
select *
into testDup
from TEST;
GO;
UPDATE Test SET Txt=(SELECT Txt FROM TestDUP WITH(NOLOCK) where ID=1)
WHERE ID=1
Warum sollte NOLOCK auf einem anderen Tisch ignoriert werden?
Oder, wenn es falsch ist, dann Frage
Wie UPDATE schreiben „NOLOCK Hinweise in dem FROM-Klausel, die in die Zieltabelle eines UPDATE oder DELETE-Anweisung anwenden“ hat, weil auch in 1) und 2) die physische Tabelle ist die gleiche, aber logisch die Quelle (in SELECT) Tabelle und Ziel (in UPDATE) Tabelle sind verschiedene.
Wie eine UPDATE-Anweisung Demonstrieren zu schreiben, die mit (NOLOCK) ignoriert wird?
Warum sollte es überhaupt ignoriert werden? Ist es ignoriert?
Oder, wenn es sich um eine falsche Frage, dann
Warum erlauben Syntax den Hinweis, die garantiert wird ignoriert werden?
Wieder einmal ist es entweder unmöglich (oder ist es?), So eine Erklärung zu schreiben, wie es in der Dokumentation geschrieben oder verstehe ich nicht das Gefühl der „ignoriert“ (Was das Gefühl, es zu ignorieren ist? Oder es zuzumin alle?) ...
UPDATE2:
Die Antworten zeigen, dass NOLOCK nicht (aktualisiert) ignoriert in der FROM-Klausel der UPDATE-Anweisung, welche von BOL docs behauptet wird [1].
Nun, das Wesen dieser Frage:
Können Sie mir kein Beispiel (Kontext), wo in der NOLOCK ignoriert FROM-Klausel der UPDATE-Anweisung Sinn gemacht hätte?
[1]
Tabelle Hinweise (Transact-SQL)
SQL Server 2008 R2
http://msdn.microsoft.com/en-us/library/ms187373.aspx
Lösung
Die FROM-Klausel einer UPDATE oder DELETE-Anweisung ist in jedem Ihrer Beispiele nicht ersichtlich. Sie haben von Klauseln in Unterabfragen, aber das ist nicht die gleiche Sache.
Hier ist eine FROM-Klausel für eine UPDATE:
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
Und, wie die Dokumentation ruft, wird die WITH (NOLOCK)
in diesem Fall ignoriert. Wie, warum dies zulässig ist, wenn sie ignoriert werden wird, würde man vermuten, dass ein solcher Hinweis in der SELECT
Version der „gleichen“ Abfrage gültig ist, und die Leute haben häufig Schreib SELECTs (um sicherzustellen, sie sind Targeting die richtige Zeilen / Spalten), und ersetzen Sie dann die SELECT
Klausel mit einem UPDATE
/ SET
Paar von Klauseln und können den Rest der Abfrage unverändert lassen.
aktualisiert, basierend auf Kommentar / "Antwort" von vgv8:
Ihr Beispiel Update noch nicht betrachtet das FROM-Klausel der UPDATE-Anweisung
Die folgende funktioniert gut, auch mit dem TABLOCKX () offen auf der anderen Verbindung:
UPDATE T SET Txt= td.Txt
FROM TEST t inner join TESTDUP td WITH (NOLOCK) on t.ID = td.ID
where t.ID = 1
Andere Tipps
Keine erforderlich Erraten.
Sybase und MS SQL Server verwenden eine interne, automatische 2PL Ressource sperren, aber mit voller Übereinstimmung mit der ISO / IEC / ANSI SQL-Standard. Die Syntax wird dumm, wenn Sie versuchen, alle möglichen Kombinationen zu verstehen, weil einige Klauseln für jeden Befehl nicht relevant sind.
Was das Handbuch versucht zu sagen, aber nicht sagen, in einfachem Englisch, ist:
- für jede Art Außenbetrieb, oder eine einzelne Abfrage innerhalb einer Transaktion, die Sie durchführen, können Sie
SET ISOLATION LEVEL
- , die angegeben werden können
UNCOMMITTED, NOLOCK, HOLDLOCK
syntax mit als auch - , wo Sie eine IL in der äußeren Abfrage haben oder eine einzelne Abfrage innerhalb einer Transaktion, wollen aber ein anderen IL für die innere Abfrage verwenden, die (Verwendung verschiedene Modulatoren auf der inneren Abfrage) durchgeführt werden können
- , so dass Sie eine Transaktion auf IL3 haben könnte ausführen, und haben eine
SELECT
innerhalb es bei IL0 oder IL-1 Ausführen
Getrennt:
- unabhängig davon, was Sie denken, Sie tun oder tun wollen, da die Verriegelung automatisch, und
ISOLATION LEVEL 3
is erforderlich fürUPDATES
undDELETES
, wobeiREAD UNCOMMITTED
undNOLOCK
nicht anwenden, und kann nicht verwendet werden , wenn man sich der Server sich ignoriert verwendet hat
Nachdem erstellt und gefüllt 2 identischen Tabellen-Test und TestDUP [1], in einer Sitzung (Fenstern von SSMS) I
execute--2)
begin tran
Select Txt from TestDUP with(TABLOCKX)
WHERE ID=1
--rollback
, die Blöcke aus einer anderen Sitzung SELECT (SSMS Fenster) auf der gleichen Tabelle, zum Beispiel:
--3.1)
select * from TestDUP
aber nicht
--3.2)
select * from TestDUP WITH(NOLOCK)
Beachten Sie, dass 3.1) blockiert ist, aber 3.2) nicht.
Obwohl, auf einem anderen Tabelle TEST Aktualisierung mit SELECT aus 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;
blockiert, weil WITH (NOLOCK), auf einer anderen Quelltabelle, in FROM-Klausel von UPDATE-Anweisung ignoriert.
Update:
--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
So ist es nun sinnvoll, aber es widerspricht der Dokumentation seit NOLOCK in FROM-Klausel von UPDATE-Anweisung nicht außer Acht gelassen wird, ist es nicht?
[1]
Erstellen 2 identisch gefüllten Tabellen-Test und 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;