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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
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:
1 2 |
UPDATE TOP (1) #Teste SET Processado = 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:
1 2 3 4 5 6 7 8 |
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:
1 2 3 4 5 6 7 8 |
;WITH CTE AS ( SELECT TOP 2 * FROM #Teste WITH(NOLOCK) ORDER BY Linha DESC ) UPDATE CTE SET Processado = 1 |
Comparando o plano de execuĂ§Ă£o:
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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
-- 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 |
É isso aĂ, pessoal!
Um abraço e atĂ© o prĂ³ximo post.
CTE (Common Table Expressions) …. Ă³tima dica … me salvou !!!