none
Acompanhar execução de update (progressbar) RRS feed

  • Pergunta

  • Boa noite a todos, a grosso modo, possuo uma stored procedure que realiza diversas operações dentro de uma transação, e entre essas, realizo um update em uma tabela 'x' de acordo com a quantidade de registros inseridos em uma outra tabela y. 

    Por exemplo:

    - É realizado um laço de repetição dentro dessa procedure que roda 9000x e dentro deste laço contem um insert por vez na tebela X. A tabela Y é atualizada de acordo com esse laço, conforme vão sendo inseridos os registros na tabela x. Entretanto, não é possível realizar um select na tabela Y para verificar a quantidade de registros que jé foram  e estão sendo inseridos em tempo de execução (timeout). Decupem a minha falta de experiência, mas creio que seja pela concorrência aos dados, gostaria da ajuda dos colegas para solucionar esse problema. 

    Identifiquei os hints with (nolock) e (readpast), lendo mais afundo, percebi que não resolveriam meu problema.

    - Esse update que realizo é por etapas, se o contador for 30 é realizado o update, caso contrário o fluxo é prosseguido. Segue a parte do código em que realizo o update:

    
       
           IF ( @AtualizaItens = 30 )
           BEGIN       
           -- Atualiza a quantidade de bens de forma sincrona na tbtarefa conforme a inserção na tbrelespecif1. (progressbar - densv.)
           UPDATE [dbo].[tbtarefa] SET [atual] = @AtualizaItens  WHERE [tarefa] = @pTarefa
           
           SET @AtualizaItens = 1
           
           END
           ELSE
           begin
           SET @AtualizaItens = @AtualizaItens + 1
           END
           


    • Editado Evertoum quinta-feira, 28 de junho de 2012 21:00
    quinta-feira, 28 de junho de 2012 20:55

Todas as Respostas

  • Evertoun,

    Nunca vi uma aplicação neste sentido, todo caso, tente alterar seu Isolation level da conexão que quer ver como esta o processo para Read Uncommmited.


    Fabrizzio A. Caputo
    MCT
    Certificações:
    Oracle OCA 11g
    MCITP SQL Server 2008 Implementation and Maintenance
    MCITP SQL Server 2008 Developer
    Blog Pessoal: www.fabrizziocaputo.wordpress.com
    Blog Empresa: www.tripletech.com.br/blog
    Twitter: @FabrizzioCaputo
    Email: fabrizzio.antoniaci@gmail.com

    sexta-feira, 29 de junho de 2012 16:56
    Moderador
  • Não tentei essa alternativa ainda, irei testar e posto o resultado. Obrigado.
    sexta-feira, 29 de junho de 2012 17:56
  • Evertoum,

    Para ler dados não commitados você pode fazer assim:

    select Campo from Tabela nolock


    View Ricardo Muramatsu's profile on LinkedIn

    sexta-feira, 29 de junho de 2012 18:19
  • Ola Ricardo,  o hint nolock até serviria. Mas serve apenas para tabelas que não estão sofrendo alterações de delete, insert ou update que é meu caso. =/


    • Editado Evertoum sexta-feira, 29 de junho de 2012 19:42
    sexta-feira, 29 de junho de 2012 19:42
  • Evertoum;

    Verdade, acho que o negócio é ir na linha do read uncommited como disse o Fabrizzio.


    View Ricardo Muramatsu's profile on LinkedIn

    sexta-feira, 29 de junho de 2012 20:19
  • Evertoum

    Se você esta em um laço acho mais prático e rápido vc criar uma tabela de controle, e a cada volta do laço você alimenta esta tabela, a tabela será menor e a leirtura será mais performática do que vc ler todo os registros da tabela que esta locada para o update.


    Att.
    Marcelo Fernandes

    MCP, MCDBA, MCSA, MCTS.
    Se útil, classifique!!!
    Me siga no twitter: @marcelodba

    segunda-feira, 2 de julho de 2012 11:53
    Moderador
  • Marcelo, mesmo eu selecionando uma única coluna desta tabela que esta sofrendo o update e essa coluna sendo indexada, o ganho de performance seria assim significativo caso eu crie uma outra tabela apenas para essa finalidade ?

    - A tabela que consulto atualmente encontra-se em uma matriz de aproximadamente 2000rows x 30columns.

    segunda-feira, 2 de julho de 2012 12:53
  • Evertum

    vc pode fazer de dois modos... criando uma tabela e dar o select nesta tabela.. ou fazer via raiserror.. veja o exemplo

    declare @qtdLaco int=0, @totLaco int = 200, @porc decimal(6,2), @msg nvarchar(100)
    declare @Progresso as table (porcentagem decimal(6,2))
    while @qtdLaco < @totLaco
    begin
    	--update em sua tabela.....
    	
    	set @qtdLaco = @qtdLaco +1
    	set @porc= convert(decimal(6,2),@qtdLaco)/@totLaco*100
    	if @porc%10 = 0
    	begin
    		--modo 1 insert em tabela
    		insert into @Progresso values(@porc)
    		set @msg = str(@porc)+' conluido!'
    		
    		--modo 2 raiserror
    		raiserror(@msg,10,1)
    	end
    end
    	
    select * from @Progresso


    Att.
    Marcelo Fernandes

    MCP, MCDBA, MCSA, MCTS.
    Se útil, classifique!!!
    Me siga no twitter: @marcelodba

    segunda-feira, 2 de julho de 2012 14:52
    Moderador
  • Evertoun,

    Nunca vi uma aplicação neste sentido, todo caso, tente alterar seu Isolation level da conexão que quer ver como esta o processo para Read Uncommmited.


    Fabrizzio A. Caputo
    MCT
    Certificações:
    Oracle OCA 11g
    MCITP SQL Server 2008 Implementation and Maintenance
    MCITP SQL Server 2008 Developer
    Blog Pessoal: www.fabrizziocaputo.wordpress.com
    Blog Empresa: www.tripletech.com.br/blog
    Twitter: @FabrizzioCaputo
    Email: fabrizzio.antoniaci@gmail.com

    Apenas como informação: Trocar o Isolation Level para READ_UNCOMMITED é o mesmo que colocar WITH (NOLOCK) na query... O comportamento é o mesmo, apenas que o Isolation level serve para a sessão inteira e o nolock apenas para aquery em questão.


    Roberto Fonseca MCT / MCITP - Database Administrator 2008 MCITP - Database Developer 2008 MCITP - Business Intelligence 2008

    segunda-feira, 2 de julho de 2012 15:47
    Moderador
  • Testei as alternativas e permaneço sem sucesso. =/

    - Enquanto a stored procedure executa as operações, tento executar o select para verificar o progresso, o resultado só me é retornado após o fim da execução de todos os processos, o progresso que me é retornado é o completo (9000),  e não como deveria (sequencial) conforme o refresh do select.

    Irei postar a stored procedure por completo e como realizo o select para verificar o progresso de inserção dos itens. (também aceito sugestões de melhoria no código, obrigado).

    ALTER PROCEDURE [dbo].[sp_relContabil_ItensConta] @pTitulo varchar(MAX) = NULL, @pTarefa decimal(15,0)= NULL, @pDataCrDrp [datetime] = NULL, @pIdValorBase_alt char(3) = NULL, @pSql [varchar] (MAX) = NULL, @pCons [bit] = NULL, -- Verifica se é relatório é por contas consolidadas. @pCriadopor [varchar] (MAX) = NULL AS DECLARE @Error varchar(MAX), @Msg varchar(MAX) SET NOCOUNT ON; SET DATEFORMAT dmy; BEGIN TRY BEGIN TRANSACTION DECLARE @tpItens TABLE ( iditem_setape uniqueidentifier ) DECLARE @tpValBase TABLE ( idtipovalbase [char] (3)) -- Variaveis auxiliares DECLARE @Comando varchar(MAX), @iditem_setape uniqueidentifier, @idtipovalbase_setape char(3), @taxa [decimal] (18,5), @taxa_alt [decimal] (18,5), @custo_consolidado [decimal] (18,5), -- recebe o custo atual do bem mais a reavaliação do mesmo. @custo_valorPadrao [decimal] (18,5), @custo_alt [decimal] (18,5), @deprec_valorPadrao [decimal] (18,5), @deprec_alt [decimal] (18,5), @liqcontabil [decimal] (18,5), @liqcontabil_alt [decimal] (18,5), @QuanTItens int, @AtualizaItens int, @NomeValBase varchar(MAX), @NomeValBase_alt varchar(MAX), @contador int -- Atribui a variavel @pDataCrDrp o ultimo dia do mês da data informada, sobreescrevendo o dia. EXEC [dbo].[sp_LastDayMon] @pDataCrDrp OUTPUT SET @NomeValBase_alt = 'NULL' IF ( @pIdValorBase_alt IS NOT NULL ) BEGIN -- Recebe o nome do valor base alternativo. SELECT @NomeValBase_alt = nome FROM [dbo].[tbTipoValBase] WHERE [idTipoValorBase] = @pIdValorBase_alt END SET @Comando = 'SELECT DISTINCT ' + CONVERT(varchar(MAX),@pTarefa) + ' as Tarefa,''' + @pTitulo + ''' as Titulo, [i].iditem_setape, [e].empresa , [fil].filial , [e].razao AS Erazao , [fil].razao AS Frazao , [cta].conta , [p].projeto , [l].LOCAL , [ce].centro , [s].secao , [d].divisao , [fa].familia , [for].fornecedor, [t].tipo , [i].item , [i].agregado , [i].chapa , [i].descricao , [i].qtde , [i].unid , [i].notafiscal , [i].movmesatu , 0 , 0 , 0 ,'''+ @NomeValBase_alt + ''', 0 , 0 , 0 , [i].dtcontabil , [i].dtaquis , [iv].dtinidepr , [fil].ult_cordep ,''' + @pCriadopor + ''' as Criadopor, [cta].[descricao] as Descricao_cta FROM dbo.tbitens AS i INNER JOIN [dbo].[tbitens_valores] [iv] ON [iv].[IdItem_setape] = [i].[IdItem_setape] INNER JOIN [dbo].[tbempresa] [e] ON [i].[IdEmpresa_setape] = [e].[IdEmpresa_setape] INNER JOIN [dbo].[tbfilial] [fil] ON [i].[IdFilial_setape] = [fil].[IdFilial_setape] LEFT JOIN dbo.tbconta AS cta ON cta.idconta_setape = i.idconta_setape LEFT JOIN dbo.tbcentro AS ce ON ce.idcentro_setape = i.idcentro_setape LEFT JOIN dbo.tbfamilia AS fa ON fa.idfamilia_setape = i.idfamilia_setape LEFT JOIN dbo.tblocal AS l ON l.idlocal_setape = i.idlocal_setape LEFT JOIN dbo.tbprojeto AS p ON p.idprojeto_setape = i.idprojeto_setape LEFT JOIN dbo.tbfornecedor AS [for] ON [for].idfornecedor_setape = i.idfornecedor_setape INNER JOIN dbo.tbprodutos AS prod ON prod.idproduto_setape = i.idproduto_setape LEFT JOIN dbo.tbsecao AS s ON i.idsecao_setape = s.idsecao_setape LEFT JOIN dbo.tbdivisao AS d ON i.iddivisao_setape = d.iddivisao_setape LEFT JOIN dbo.tbclasse [cl] ON [i].[IdClasse_setape] = [cl].[IdClasse_setape] INNER JOIN [dbo].[tbIdent_sistema] [is] ON [is].[Ident_sistema] = [i].[ident_sistema] INNER JOIN [dbo].[tbtipo] [t] ON [t].[idtipo_setape] = [cta].[Idtipo_setape] WHERE [i].[baixado] != 1 and '+ @pSql INSERT INTO [dbo].[tbrelespecif1] ([tarefa], [titulo], [iditem_setape], [empresa], [filial], [Erazao], [Frazao], [conta], [projeto], [LOCAL], [centro], [secao], [divisao], [familia], [fornecedor], [tipo], [item], [agregado], [chapa], [descricao], [qtde], [unid], [notafiscal], [movmesatu], [custo], [deprec], [taxa], [nome_alt], [custo_alt], [deprec_alt], [taxa_alt], [dtcontabil], [dtaquis], [dtinidepr], [ult_cordep], [criadopor], [descricao_cta]) EXEC (@Comando) SET @AtualizaItens = 0; -- Armazena na temp todos os itens que utilizam a conta informada. INSERT INTO @tpItens SELECT iditem_setape FROM [dbo].[tbrelespecif1] WHERE [tarefa] = @pTarefa -- Armazena a quantidade de itens por conta (progress bar) SELECT @QuanTItens = COUNT(*) FROM @tpItens -- atualiza na tbtarefa quantidade total de itens para a conta informada UPDATE [dbo].[tbtarefa] SET [total] = @QuanTItens WHERE [tarefa] = @pTarefa WHILE ( SELECT COUNT(*) FROM @tpItens) > 0 BEGIN -- Inicia as variaves com valor 0. SET @custo_consolidado = 0; SET @custo_alt = 0; SET @deprec_alt = 0; SET @taxa_alt = 0; SET @liqcontabil_alt = 0; SELECT top 1 @iditem_setape = iditem_setape FROM @tpItens -- Recebe o id do valor base padrão e o nome correspondente do mesmo SELECT @idtipovalbase_setape = [a].[IdTipoValorBase], @NomeValBase = [nome] FROM [dbo].[tbAcesso_tipovalbase] [a] INNER JOIN [dbo].[tbTipoValBase] [vb] ON [a].[IdTipoValorBase] = [vb].[idTipoValorBase] INNER JOIN [dbo].[tbempresa] [e] ON [a].[IdEmpresa_setape] = [e].[IdEmpresa_setape] INNER JOIN [dbo].[tbitens] [i] ON [i].[IdEmpresa_setape] = [e].[IdEmpresa_setape] WHERE [IdItem_setape] = @iditem_setape AND [ValBasePadrao] = 1 -- Custo e depreciação calculado sob o valor base padrão da empresa que o bem utiliza. -- SELECT @custo_valorPadrao = valor FROM [dbo].[fnObtemCustoItem] ( @iditem_setape, @idtipovalbase_setape, @pDataCrDrp, NULL, NULL, NULL ) SELECT @custo_valorPadrao = [custo], @deprec_valorPadrao = [valorDeprecAcumulado] FROM [dbo].[fnObtemDeprecItem] ( @iditem_setape, @idtipovalbase_setape, @pDataCrDrp, NULL, NULL, NULL, 1 ) -- seleciona a taxa do ultimo dia em anterior a data informada pelo usuário em relação a moeda padrão. SELECT TOP 1 @taxa = [taxa] FROM [dbo].[tbmovim_valores] [mv] INNER JOIN [dbo].[tbAcesso_tipovalbase] [a] ON [mv].[idtipovalorbase_setape] = [a].[IdTipoValorBase] GROUP BY [mv].[taxa], [mv].[master_mov], [mv].[IdItem_setape], [a].[ValBasePadrao] HAVING MAX([mv].[dtcontabil]) < @pDataCrDrp AND [mv].[IdItem_setape] = @iditem_setape AND [a].[ValBasePadrao] = 1 ORDER BY [mv].[master_mov] DESC -- Define o valor liquido contábil para o valor base padrão SET @liqcontabil = (@custo_valorPadrao - @deprec_valorPadrao) -- Verifica se o relatório é de contas consolidadas. IF ( @pCons IS NOT NULL) BEGIN DECLARE @tempIdsValorBase TABLE ( idvalorbase [char](3) ) DECLARE @valor [decimal] (18,5), -- variavel auxiliar que recebe o custo de reavaliação de cada bem @custo_reav [decimal] (18,5), -- variavel que armazena o somatorio da(s) reavaliação(ões) @idvalorbase[char] (3) -- recebe o id do valor base SET @custo_reav = 0; -- insere na variavel table o id da reavaliação, ou os ids, caso haja mais de uma reavaliação para o item informado. INSERT INTO @tempIdsValorBase SELECT [tv].[idTipoValorBase] FROM [dbo].[tbmovim_valores] [mv] INNER JOIN [dbo].[tbTipoValBase] [tv] ON [mv].[idtipovalorbase_setape] = [tv].[idTipoValorBase] WHERE [tv].[reav] = 1 AND [mv].[IdItem_setape] = @iditem_setape GROUP BY [tv].[idTipoValorBase] WHILE ( SELECT COUNT (*) from @tempIdsValorBase ) > 0 BEGIN SELECT @idvalorbase = idvalorbase FROM @tempIdsValorBase -- Retorna o custo da reavaliação do item SELECT @valor = valor FROM [dbo].[fnObtemCustoItem] ( @iditem_setape, NULL, @pDataCrDrp, NULL, NULL, 1 ) -- Armazena o custo da reavaliação do bem ou de todas reavaliações para este bem. SET @custo_reav = @custo_reav + @valor DELETE FROM @tempIdsValorBase WHERE [idvalorbase] = @idvalorbase END -- Atribui a variavel @custo_consolidado o custo atual do bem mais a(s) reavaliação(ões) SET @custo_consolidado = @custo_valorPadrao + @custo_reav END -- Verifica se o usuário solicitou o cálculo do custo sob uma moeda alternativa, (não padrão). IF ( @pIdValorBase_alt IS NOT NULL ) BEGIN -- Calcula o Custo e depreciação sob o valor alternativo informado pelo usuário. -- SELECT @custo_alt = valor FROM [dbo].[fnObtemCustoItem] ( @iditem_setape, @pIdValorBase_alt, @pDataCrDrp, NULL, NULL ) SELECT @custo_valorPadrao = [custo], @deprec_valorPadrao = [valorDeprecAcumulado] FROM [dbo].[fnObtemDeprecItem] ( @iditem_setape, @idtipovalbase_setape, @pDataCrDrp, NULL, NULL, @pCons, 1 ) -- seleciona a taxa do ultimo dia em relação a data informada pelo usuário para a moeda alternativa. SELECT TOP 1 @taxa_alt = [taxa] FROM [dbo].[tbmovim_valores] [mv] INNER JOIN [dbo].[tbAcesso_tipovalbase] [a] ON [mv].[idtipovalorbase_setape] = [a].[IdTipoValorBase] GROUP BY [mv].[taxa], [mv].[master_mov], [mv].[IdItem_setape], [a].[IdTipoValorBase] HAVING MAX([mv].[dtcontabil]) < @pDataCrDrp AND [mv].[IdItem_setape] = @iditem_setape AND [a].[IdTipoValorBase] = @pIdValorBase_alt ORDER BY [mv].[master_mov] DESC -- Define o liquido contábil para o valor adicional especificado no parâmetro SET @liqcontabil_alt = (@custo_alt - @deprec_alt) END -- Atualiza nome, custo consolidado, custo, depreciação e taxa para moeda padrão e se solicitado moeda alternativa, para cada seu respectivo item. UPDATE [dbo].[tbrelespecif1] SET [nome] = @NomeValBase, [custo_cons] = @custo_consolidado, [custo] = @custo_valorPadrao, [deprec] = @deprec_valorPadrao, [taxa] = @taxa, [liqcontabil] = @liqcontabil, [custo_alt] = @custo_alt, [deprec_alt] = @deprec_alt, [taxa_alt] = @taxa_alt, [liqcontabil_alt] = @liqcontabil_alt WHERE [tarefa] = @pTarefa AND [iditem_setape] = @iditem_setape --declare @qtdLaco int=0, -- @totLaco int = 200, -- @porc decimal(6,2) -- -- --update em sua tabela..... -- set @qtdLaco = @qtdLaco +1 -- set @porc= convert(decimal(6,2),@qtdLaco)/@totLaco*100 -- if @porc%10 = 0 -- BEGIN -- --modo 1 insert em tabela -- --insert into @Progresso values(@porc) -- UPDATE [dbo].[tbtarefa] SET [atual] = @porc -- WHERE [tarefa] = @pTarefa -- -- --modo 2 raiserror -- --raiserror(@msg2,10,1) -- end IF ( @AtualizaItens = 30 ) BEGIN -- Atualiza a quantidade de bens de forma sincrona na tbtarefa conforme a inserção na tbrelespecif1. (progressbar - densv.) UPDATE [dbo].[tbtarefa] SET [atual] = @AtualizaItens WHERE [tarefa] = @pTarefa SET @AtualizaItens = 1 END ELSE begin SET @AtualizaItens = @AtualizaItens + 1 END DELETE FROM @tpItens WHERE iditem_Setape = @iditem_setape END COMMIT TRANSACTION SET NOCOUNT OFF; END TRY BEGIN CATCH SELECT @Error = ERROR_MESSAGE(); RAISERROR (@Error, 11, 2); ROLLBACK TRANSACTION END CATCH GO

    select atual from tbtarefa where tarefa = 1 -- procuro visualizar a quantidade que esta sendo atualizada conforme o loop,

    entretando só me é retornado o valor final após a execução total.





    • Editado Evertoum segunda-feira, 2 de julho de 2012 17:20
    segunda-feira, 2 de julho de 2012 17:12