none
Problema de performance com cursor RRS feed

  • Pergunta

  • Pessoal, estou com um sério problema de performance!

    Meu cenário é o seguinte:

    Tenho 2 tabelas. Vamos chamá-las de A e B.

    Eu preciso enriquecer a tabela A, com uma informação que existe na tabela B, que está no campo Unique_ID. Minha regra de negócio diz que este Unique_ID só poderá ser utilizado em um único registro na tabela A. Sendo assim, cada vez que eu utilizo um Unique_ID para enriquecer a tabela A, eu preciso marcar este Unique_ID como já utilizado na tabela B.

    A única forma que encontrei de fazer isso é com cursor, pois cada registro que eu enriqueço na tabela A, eu posso fazer um update na B e marcar aquele Unique_ID como já utilizado. Assim, no próximo registro a ser enriquecido na tabela A, este Unique_ID não será mais um candidato, pois o select do enriquecimento possui uma cláusula where que impede que ele seja utilizado novamente.

     Gostaria então que olhassem meu cursor e dessem alguma dica de melhoria, pois não sou bom com cursores.

    Vou comentar no código o que é feito e minhas dúvidas. Vejam:

    		----------------------------------------------------------------------------------------------------
    		-- '1.Basico' --------------------------------------------------------------------------------------
    		----------------------------------------------------------------------------------------------------
    		declare _cursor Cursor
    			local
    			keyset
    			-- seleciono a tabela que será enriquecida, a que eu chamei de A<br/>			for select [A.Id], [B.Id], Descricao from AinB_Study
    				where
    					 [B.Id] is null
    					 and Descricao is null<br/>			-- quando eu vou armazenar a informação vinda da tabela B, eu atualizo a tabela A, mas sem usar o current record. Se eu tirar o "for update", terei ganho?
    			for update 
    
    		open _cursor
    		fetch next from _cursor INTO @A_Id, @B_Id, @Descricao
    		<br/>		-- percorro cada registro da tabela A	
    		while @@FETCH_STATUS = 0
    		begin
    			-- leio o Unique_ID da tabela B
    			set @B_Id =
    				(select Unique_ID ... )
    			<br/>			-- se encontrar o Unique_ID, salvo na tabela A e marco ele como utilizado na tabela B
    			if @B_Id is not null
    			begin
    				-- atualiza a tabela A com o Unique_ID vindo de B
    				update AinB_Study
    				set
    					Descricao = '1.Basico',
    					[B.Id] = @B_Id
    				where [A.id] = @A_Id
    
    				-- atualizo o Unique_ID utilizado, dizendo que ele já foi usado<br/>				update CDRs_Comutacao
    				set
    					Used = 1
    				where
    					Unique_ID = @B_Id
    			end	
    			
    			fetch next from _cursor INTO @A_Id, @B_Id, @Descricao
    		end
    		close _cursor
    		deallocate _cursor 
    
    Espero que alguém possa me ajuda!
    Se essa resposta é a solução do seu problema, por favor, marque-a como SOLUÇÃO!
    quinta-feira, 17 de março de 2011 01:28

Respostas

  • Felipe,

    Então, não seria tabelas distintas? Tabela A e Tabela B?

    Não seria o caso de fazer um Join recursivo utilizando neste caso a mesma table?


    Pedro Antonio Galvão Junior [MVP | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados | SorBR.Net | Professor Universitário | MSIT.com]
    • Marcado como Resposta Richard Juhasz segunda-feira, 28 de março de 2011 19:54
    domingo, 20 de março de 2011 01:12

Todas as Respostas

  • Felipe

     

    Acho que o que vc precisa pode ser feito com um Update com Join, sem precisar de uma estrutura de repetição, com certeza você ganharia em performance pois o comanda alteraria as linhas em lote.

    Porém, para que eu o ajude preciso que poste a definições das tabelas (DDL).Isso seri possível ?

     

    Victor Perez

    quinta-feira, 17 de março de 2011 22:22
  • Felipe

    Com certeza você pode utilizar um update com join, desse jeito você ganharia em performance.Mas para que eu te ajude preciso das definições das tabelas A e B (DDL).

     

    Victor Perez

     

    quinta-feira, 17 de março de 2011 22:24
  • Eu fazia update com JOIN. A questão é que, quando eu utilizo uma informação da tabela B, eu necessariamente não posso nunca mais utilizá-la e, para isso eu preciso fazer um update na tabela B, e só então continuar atualizando a tabela A, buscando informação na tabela B.

    Update não tem como fazer isso. É algo da regra de negócio que me levou a utilizar cursor.
    Se houver alguma outra forma de percorrer os dados de um select sem cursor, já terei uma melhoria de performance significativa.


    Se essa resposta é a solução do seu problema, por favor, marque-a como SOLUÇÃO!
    sexta-feira, 18 de março de 2011 13:08
  • Cursor não escala para grandes tabelas....

    o SQL Server trabalha com bloco de dados, quando usamos cursor, ele trabalha linha a linha....por isso que demora...

    []'s!

     


    http://www.diaadiasql.com.br
    sexta-feira, 18 de março de 2011 15:09
  • Felipe,

    Então, não seria tabelas distintas? Tabela A e Tabela B?

    Não seria o caso de fazer um Join recursivo utilizando neste caso a mesma table?


    Pedro Antonio Galvão Junior [MVP | Microsoft Evangelist | Microsoft Partner | Engenheiro de Softwares | Especialista em Banco de Dados | SorBR.Net | Professor Universitário | MSIT.com]
    • Marcado como Resposta Richard Juhasz segunda-feira, 28 de março de 2011 19:54
    domingo, 20 de março de 2011 01:12
  • Já tentou montar uma trigger de insert na tabela A?

    faça um insert nomal sem informar o ID e sem joins, na trigger você localiza um ID vago na tabela B, atribui o valor do ID encontrado em A e realiza  o update na tabela B indicando como ID já utilizado.

     


    Marquinhos Não esqueça de qualificar a resposta.
    terça-feira, 22 de março de 2011 18:58