Pessoal, vamos pensar set based ?


Galerinha, que acham da gente mudar o pensamento.
 
Tive um caso ontem bem interessante .
 
Uma certa empresa tinha um processo que executava todo dia, e demorava entre 40 a 50 minutos.
 
Quando abri a proc estava assim :
 

declare @codigo int
declare @valor float
 
declare ccursor cursor for
select codigo,
         valor
from tab1

open ccursor

fetch next from ccursor into @codigo,@valor

WHILE @@FETCH_STATUS = 0
BEGIN
 if exists (select 1 from tab2 where codigo = @codigo)
  update tab2 set valortab2 = valortab1 + @valor where codigo = @codigo
 else
  insert into tab2(codigo, valortab1,valortab2) values (@codigo,@valor,0)
  
 fetch next from ccursor into @codigo,@valor

end

close ccursor
deallocate ccursor 

 

Ou seja, para cada linha de tab1 procurava-se em TAB2. Se existisse atualizava o valor, se não inseria uma nova linha.

Este processo assim, para 980 mil linhas na TAB1, demorava 47 minutos.

Bom, este é o tipico pensamento llinha a linha, que a maiora de desenvolvedore seniors tem pois viemos de uma epoca que os recursos eram limitados neste aspecto.

Poxa eu fui programador clipper muitos anos, era seek e do while.

Mas e se a gente mudasse o pensamento ?

E se a gente atualizasse o que existe e inserisse o que não existe ?…

Vamos mais a fundo e se a gente atualizasse o que existe, guardasse o codigo destas linhas atualizadas numa tabela e inserisse na tab2 as que nao existem no join da tab1 com esta nova tabela.

Vamos lá

declare @tabela table (codigo int)

update  a
set        a.valortab2 = a.valortab1 + b.valor
OUTPUT inserted.codigo INTO @tabela
from tab2 a,
        tab1 b
where a.codigo = b.codigo

insert into tab2( codigo,
                        valortab1,
                        valortab2
                      )
select a.codigo,
         a.valor,
         0
from  tab1 a
where not exists ( select 1
                           from @tabela b
                           where a.codigo = b.codigo
                         )

Esta alteração de pensamento, passou para 7 segundos, de 5 a 7 em média.

Usando a clausula output (pois era 2005..se fosse 2008 eu usaria o merge) eu coloquei na @tabelas as linhas que foram atualizadas e depois inseri as que nao tivessem no join dela com a tab1

O que eu fiz ?..nada de milagres ou tecnicas extraordinárias de tuning…simplesmente pensei SET BASED…conjunto de linhas e nao linha a linha.

Grande abraço a todos

 

Falowwww

 

About Laerte Junior

Laerte Junior Laerte Junior is a SQL Server specialist and an active member of WW SQL Server and the Windows PowerShell community. He also is a huge Star Wars fan (yes, he has the Darth Vader´s Helmet with the voice changer). He has a passion for DC comics and living the simple life. "May The Force be with all of us"
This entry was posted in Algo que Esqueci de Categorizar. Bookmark the permalink.

1 Response to Pessoal, vamos pensar set based ?

  1. Marco Octávio says:

    Realmente isso é algo muito importante. No local onde sou DBA, estou fazendo um projeto de Tuning e um dos objetivos é verificar as consultas mais onerosas e base e tentar otimizá-las. A grande maioria das consultas estão lentas justamente por não serem SET BASED, e sim ROW BASED.

    Uma mesmo estava demorando em média uns 20 min. Após alterações ela baixou o tempo para aproximadamente 4 min.

    Abraços.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s