¡Hola, chicos!
En este artículo me gustaría demostrar en la práctica el uso de 2 sugerencias de consulta ampliamente utilizadas por los desarrolladores para evitar bloqueos al leer datos, que son NOLOCK y READPAST, y demostrar de manera efectiva el efecto de estas sugerencias en una consulta.

La idea de escribir este artículo surgió de una pregunta enviada al grupo. “Servidor SQL – DBA”, de Telegram, y también unas viejas ganas de escribir sobre esto cada vez que veo entornos donde casi todas las consultas tienen NOLOCK.

Después de leer esta publicación, podrás entender exactamente cómo funcionan estos 2 consejos y los utilizarás sabiamente y sólo cuando sea conveniente. No es necesario poner NOLOCK/READPAST en todas tus consultas, ¡eh!

Si su entorno tiene mucha competencia y los bloqueos, bloqueos y puntos muertos son frecuentes y un problema para usted, le sugiero pensar en un enfoque más completo que usar estas sugerencias, que sería usar el modo de aislamiento de instantánea de lectura confirmada (RCSI), que le permite usar el modo de lectura confirmada sin bloquear las lecturas cuando ocurren transacciones abiertas. Como no todo es color de rosas, existen algunos efectos secundarios al utilizar este modo, como una posible caída del rendimiento. Si quieres saber más sobre él, te sugiero leer el artículo. Leer aislamiento de instantáneas confirmadas: escritores bloquean escritores (RCSI), del gran maestro Brent Ozar.

Para demostrar cómo funcionan NOLOCK y READPAST, creemos una tabla con algunos registros:

IF (OBJECT_ID('dbo.Teste_Nolock') IS NOT NULL) DROP TABLE dbo.Teste_Nolock
CREATE TABLE dbo.Teste_Nolock (
    Id INT IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED,
    Nome VARCHAR(100)
)

INSERT INTO dbo.Teste_Nolock
VALUES ('Dirceu'), ('Resende'), ('Consultor'), ('SQL Server'), ('Power BI'), ('SSRS'), ('SSIS'), ('SSAS'), ('Blog')

Tabla actual:

[Vídeo] – NOLOCK frente a READPAST

NOLOCK o LEER NO COMPROMETIDO

Modo de aislamiento muy conocido por los DEV, que permite devolver los datos actuales de la tabla sin tener que esperar el final de las transacciones en curso, haciendo una “lectura sucia” de los datos, es decir, si hay transacciones que cambian los datos en las tablas que se consultan, estos registros se devolverán tal como están, incluso si las transacciones aún están abiertas (no se ha realizado ningún compromiso ni reversión) y estos datos aún no son definitivos.

Este tipo de lectura puede ser muy útil en casos de alta competencia y la aparición de bloqueos y puntos muertos en el entorno, pero tenga en cuenta los efectos secundarios del uso de la sugerencia NOLOCK (equivalente al comando SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED o FROM(READUNCOMMITTED)).

Ejemplo práctico de NOLOCK

En una sesión de SQL Server Management Studio (SSMS), ejecute el siguiente comando:

BEGIN TRANSACTION

UPDATE dbo.Teste_Nolock
SET Nome = 'Teste Nolock'
WHERE Nome = 'Dirceu'

Abra otra sesión en SSMS y ejecute el siguiente comando:

BEGIN TRANSACTION

INSERT INTO dbo.Teste_Nolock
VALUES('Teste Nolock2')

Tenga en cuenta que estas 2 sesiones abrieron una transacción, realizaron cambios en los datos, pero aún no se han realizado ni la confirmación ni la reversión, es decir, estos datos modificados aún pueden considerarse datos "temporales", ya que no son datos confirmados ni confirmados. Si hay un problema en el flujo o el usuario simplemente quiere deshacer estos cambios, puede revertir estas transacciones y estos datos insertados/cambiados nunca existieron “oficialmente”.

Aun así, si aún en este escenario, abres una nueva sesión e intentas consultar los datos, verás que tu sesión esperará indefinidamente, hasta que se completen las transacciones con COMMIT o ROLLBACK. Esto ocurre porque el modo de lectura predeterminado de SQL Server es LEER COMMITED, es decir, solo devuelve datos que ya se han confirmado en la base de datos.

Usando la sugerencia NOLOCK, puede devolver datos sin tener que esperar a que se completen estas transacciones, pero los datos que aún no se han confirmado se devolverán como si ya fueran datos definitivos:

Si estas sesiones realizan una ROLLBACK de los datos, terminará consultando datos que en realidad nunca existieron. Esto en un informe podría terminar produciendo resultados incorrectos.

LEER PASADO

Otra forma de leer datos de tablas que están siendo modificadas por transacciones abiertas sin tener que esperar a que finalicen estas transacciones es utilizar la sugerencia READPAST. A diferencia de NOLOCK, READPAST no permite lecturas sucias (guardar excepciones), pero comprenda cómo funciona: READPAST solo devolverá datos que no se vean afectados por transacciones abiertas.

Ejemplo práctico de NOLOCK

En una sesión de SQL Server Management Studio (SSMS), ejecute el siguiente comando:

BEGIN TRANSACTION

UPDATE dbo.Teste_Nolock
SET Nome = 'Teste Nolock'
WHERE Nome = 'Dirceu'

Abra otra sesión en SSMS y ejecute el siguiente comando:

BEGIN TRANSACTION

INSERT INTO dbo.Teste_Nolock
VALUES('Teste Nolock2')

Y ahora, intentemos leer los datos usando la sugerencia READPAST y veamos cómo se devolverán los registros no confirmados:

Con la sugerencia READPAST, puede devolver datos sin tener que esperar a que se completen estas transacciones, pero SELECT no devolverá los datos que aún no se han confirmado, es decir, los registros se pueden ignorar en este modo de lectura. Cuando utiliza funciones de agregación, como SUM, MAX, MIN, en este modo de lectura, los valores finales pueden ser muy diferentes de los valores reales, ya que los registros pueden ignorarse.

¿NOLOCK o READPAST?

Para concluir y resumir este artículo, tanto NOLOCK como READPAST tienen como principal justificación de uso, la posibilidad de leer datos en tablas sin tener que esperar a que se completen las transacciones activas, minimizando la ocurrencia de bloqueos y bloqueos, incluso si estos registros están siendo modificados por estas transacciones.

Cuando se utiliza NOLOCK (o READ UNCOMMITED), si la tabla tiene 10 filas y ACTUALIZACIÓN/ELIMINACIÓN cambia 3, el comando SELECT devolverá las 10 filas, con los datos "actualizados". SELECT también devolverá las nuevas filas insertadas que aún no se han confirmado.

Cuando se utiliza READPAST, si la tabla tiene 10 filas y ACTUALIZACIÓN/ELIMINACIÓN cambia 3, el comando SELECT solo devolverá las 7 filas que no se modifican. SELECT NO devolverá las nuevas filas insertadas que aún no se hayan confirmado.

Referencias:
https://docs.microsoft.com/pt-br/sql/t-sql/language-elements/transaction-isolation-levels?view=sql-server-2017
https://www.tiagoneves.net/blog/isolation-level-no-sql-server/
http://www.diegonogare.net/2013/01/transaction-isolation-level-voc-est-usando-certo/
https://imasters.com.br/data/entendê-transaction-isolation-level-no-sql-server