¿Por NOLOCK se ignora “en la cláusula FROM que se aplican a la tabla de destino de una instrucción UPDATE o DELETE”?
-
29-09-2019 - |
Pregunta
Estoy confundido por la frase BOL:
"READUNCOMMITTED y NOLOCK no se pueden especificar para las tablas modificadas por inserción, actualización o las operaciones de borrado. Optimizador de consultas de SQL Server ignora los consejos READUNCOMMITTED y NOLOCK en la cláusula FROM que se aplican a la tabla de destino de una instrucción UPDATE o DELETE" [1]
Por ejemplo, si escribo
--script 1)
UPDATE Test SET Txt=(Select Txt from TEST WITH(NOLOCK) where ID=1)
WHERE ID=1
se ejecuta sin errores (o advertencias) y es probablemente equivalente a
--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;
que también se ejecuta sin errores o advertencias.
Es equivalente?
La tabla es el mismo, pero en DE es lógicamente no la tabla de origen de la tabla de destino Podría tener re-escrito 1) con una tabla de origen diferente, como otra tabla (física):
--script 3)
select *
into testDup
from TEST;
GO;
UPDATE Test SET Txt=(SELECT Txt FROM TestDUP WITH(NOLOCK) where ID=1)
WHERE ID=1
¿Por qué debería ser ignorado NOLOCK en otra mesa?
O, si está mal, pregunta entonces
Cómo escribir ACTUALIZACIÓN tener "indicios NOLOCK en la cláusula FROM que se aplican a la tabla de destino de una instrucción UPDATE o DELETE" porque incluso en 1) y 2) la tabla física es la misma, pero lógicamente la fuente (SELECCIONAR) mesa y objetivo (UPDATE) tabla son diferentes.
Cómo escribir una instrucción UPDATE que demuestra CON (NOLOCK) se ignora?
¿Por qué debe ser ignorada en absoluto? Se ignoró?
O, si se trata de una pregunta mal, entonces
¿Por qué la sintaxis permiten la pista que está garantizado para ser ignorado?
Una vez más, tampoco es imposible (o es?) Para escribir tal declaración una como está escrito en la documentación o que no entiendo el sentido de "ignora" (¿Cuál es el sentido de ignorarlo? O tenerlo en todos?) ...
Update2:
Las respuestas muestran que NOLOCK no es (actualiza) ignorado en la cláusula de la instrucción UPDATE lo que afirma docs BOL [1] A partir.
Pues bien, la esencia de esta pregunta: ¿
¿Me puede dar algún ejemplo (contexto) en la que haciendo caso omiso de NOLOCK en la cláusula FROM de la instrucción UPDATE hubiera tenido sentido?
[1] |
Sugerencias de tabla (Transact-SQL)
SQL Server 2008 R2
http://msdn.microsoft.com/en-us/library/ms187373.aspx
Solución
La cláusula FROM de una instrucción UPDATE o DELETE no es evidente en cualquiera de sus ejemplos. Que se tiene de cláusulas en subconsultas, pero los que no son la misma cosa.
Aquí hay una cláusula FROM para una actualización:
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
Y, como la documentación dice en voz alta, la WITH (NOLOCK)
se tendrá en cuenta en este caso. En cuanto a por qué esto es permitido si va a ser ignorado, una conjetura sería que un indicio sería válida en la versión SELECT
de la "misma" consulta, y la gente no SELECTs frecuencia de escritura (para asegurarse de que están dirigidas a la correcta filas / columnas), y luego vuelva a colocar la cláusula SELECT
con un par UPDATE
/ SET
de las cláusulas, y pueden dejar el resto de la consulta inalterada.
Actualización sobre la base de comentario / "respuesta" de vgv8:
Su actualización ejemplo, todavía no está mirando a la cláusula de la instrucción UPDATE FROM
La siguiente funciona bien, incluso con la TABLOCKX () abierta en la otra conexión:
UPDATE T SET Txt= td.Txt
FROM TEST t inner join TESTDUP td WITH (NOLOCK) on t.ID = td.ID
where t.ID = 1
Otros consejos
No se requiere adivinar.
Sybase y el uso del servidor de MS SQL una, el bloqueo de recursos 2PL automática interna, pero con el pleno cumplimiento de la norma ANSI SQL estándar ISO / IEC /. La sintaxis se pone tonta cuando intenta comprender todas las combinaciones posibles, porque algunas cláusulas no son relevantes para cada comando.
Lo que el manual está tratando de decir, pero no dice en Inglés sencillo, es:
- para cualquier operación externa, o una sola consulta dentro de una transacción, que está realizando, puede
SET ISOLATION LEVEL
- que se pueden especificar utilizando
UNCOMMITTED, NOLOCK, HOLDLOCK
syntax así - donde tiene uno IL en la consulta externa, o una sola consulta dentro de una transacción, pero desea utilizar un IL diferente para la consulta interna, que se puede hacer (uso de diferentes moduladores en la consulta interna)
- por lo que podría tener una transacción de ejecución en IL-3, y tienen una
SELECT
dentro de ella la ejecución de al IL0 o IL-1
Por separado:
- independientemente de lo que usted piensa que está haciendo, o desea realizar, ya que el bloqueo es automático, y
ISOLATION LEVEL 3
is requerida paraUPDATES
yDELETES
, enREAD UNCOMMITTED
yNOLOCK
no se aplican, y no se puede utilizar , si los ha utilizado el servidor ignorará
Después de haber creado y llenado 2 tablas idénticas de prueba y TestDUP [1], en una sola sesión (ventanas de SSMS) ejecuto
--2)
begin tran
Select Txt from TestDUP with(TABLOCKX)
WHERE ID=1
--rollback
que bloquea Selecciona de otra sesión (ventana de SSMS) en la misma mesa, por ejemplo:
--3.1)
select * from TestDUP
pero no
--3.2)
select * from TestDUP WITH(NOLOCK)
Tenga en cuenta que 3.1) está bloqueado, pero 3.2) no lo es.
Sin embargo, la actualización en otra prueba de la tabla usando SELECT desde 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;
está bloqueado debido CON (NOLOCK), en otra tabla de origen, se ignora en la cláusula FROM de la instrucción UPDATE.
Actualización:
--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
Por lo tanto, ahora tiene sentido pero contradice a la documentación ya NOLOCK en la cláusula FROM de la instrucción UPDATE NO se tiene en cuenta, no es cierto?
[1] | Crear 2 mesas llenas de prueba de forma idéntica y 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;