Olá pessoal,
Bom dia!

Hoje vou mostrar pra vocês como atualizar ou apagar um número fixo de registros de uma tabela, que pode ser utilizado para manipular os dados da tabela sem travá-la por muito tempo durante a execução das queries.

Geração de uma base simples

Vou demonstrar como criar a base de testes que iremos utilizar neste post

IF (OBJECT_ID('tempdb..#Teste') IS NOT NULL) DROP TABLE #Teste
CREATE TABLE #Teste (
    Linha INT IDENTITY(1, 1),
    Valor FLOAT,
    Processado BIT DEFAULT 0
)

INSERT INTO #Teste(Valor)
SELECT 125.99

INSERT INTO #Teste(Valor)
SELECT 457.64

INSERT INTO #Teste(Valor)
SELECT 124.77

INSERT INTO #Teste(Valor)
SELECT 3687.48

INSERT INTO #Teste(Valor)
SELECT 14.47

INSERT INTO #Teste(Valor)
SELECT 758.51

INSERT INTO #Teste(Valor)
SELECT 288.05

UPDATE TOP

Muita gente não sabe, mas a instrução UPDATE suporta o uso do TOP para delimitar a quantidade de registros a ser atualizada:

UPDATE TOP (1) #Teste
SET Processado = 1

SQL Server - Update TOP 1
SQL Server - Update TOP 1

Embora bem simples, esse comando pode acabar enganando você. Isso acontece porque quando você utiliza um comando TOP sem utilizar o ORDER BY, o resultado não é determinístico. Toda vez que você for utilizar um TOP, você deve utilizar um ORDER BY para indicar para o banco como irá ordenar os resultados e depois filtrar utilizando o TOP. Mesmo que a tabela tenha índice clustered, isso não garante que os dados serão ordenados utilizando o índice clustered ou com o RowID no caso de tabelas HEAP.

Apesar o UPDATE suportar o TOP, ele não suporta o ORDER BY. Para resolver essa situação, podemos realizar esse mesmo update desta forma:

UPDATE A 
SET Processado = 1
FROM #Teste A
JOIN (
    SELECT TOP 2 *
    FROM #Teste WITH(NOLOCK)
    ORDER BY Linha DESC
) B ON B.Linha = A.Linha

Ou pode ser feito ainda com CTE (Common Table Expressions), que é uma forma mais elegante e eficiente:

;WITH CTE AS 
( 
    SELECT TOP 2 *
    FROM #Teste	WITH(NOLOCK)
    ORDER BY Linha DESC
) 
UPDATE CTE 
SET Processado = 1

Resultado:

SQL Server - Update TOP 1 _2
SQL Server - Update TOP 1 _2

Comparando o plano de execução:

SQL Server - Update TOP 1 Execution Plan
SQL Server - Update TOP 1 Execution Plan

SQL Server - Update TOP 1 Execution Plan 2
SQL Server - Update TOP 1 Execution Plan 2

Conforme indicado acima, a solução utilizando o CTE é mais elegante e performática, sendo executada em um tempo menor e consumindo menos disco e CPU

DELETE TOP

Assim como utilizamos no UPDATE, podemos utilizar o TOP no próprio DELETE, correndo o risco de apagar registros aleatórios e também podemos utilizar o ORDER BY tanto o JOIN no update quanto o CTE para filtrar e limitar os registros que serão removidos:

-- Apagando o primeiro registro (não há garantias de ser o primeiro registro)
DELETE TOP(1)
FROM #Teste A

-- Apagando o último registro utilizando JOIN
DELETE A FROM #Teste A
JOIN (
    SELECT TOP 1 * 
    FROM #Teste WITH(NOLOCK) 
    ORDER BY Linha DESC
) B ON B.Linha = A.Linha

-- Apagando o último registro utilizando CTE
;WITH CTE AS 
( 
    SELECT TOP 1 * 
    FROM #Teste WITH(NOLOCK) 
    ORDER BY Linha DESC
) 
DELETE CTE

Exemplo:

SQL Server - Delete TOP 1_3
SQL Server - Delete TOP 1_3

É isso aí, pessoal!
Um abraço e até o próximo post.