{"id":910,"date":"2011-06-29T23:11:57","date_gmt":"2011-06-30T01:11:57","guid":{"rendered":"http:\/\/fabriciolima.net\/blog\/?p=910"},"modified":"2017-12-21T09:32:34","modified_gmt":"2017-12-21T11:32:34","slug":"rotina-para-atualizar-as-estatisticas-do-seu-banco-de-dados","status":"publish","type":"post","link":"https:\/\/fabriciolima.net\/blog\/2011\/06\/29\/rotina-para-atualizar-as-estatisticas-do-seu-banco-de-dados\/","title":{"rendered":"Rotina para Atualizar as Estat\u00edsticas do seu Banco de Dados"},"content":{"rendered":"<p>Fala Pessoal,<\/p>\n<p>N\u00f3s sempre ouvimos que as estat\u00edsticas de um Banco de Dados SQL Server devem estar sempre atualizadas para que o Query Optimizer possa gerar o melhor plano de execu\u00e7\u00e3o para nossas consultas. Para isso, devemos habilitar a op\u00e7\u00e3o <strong>&#8216;Auto Update Statistics&#8217;<\/strong> nas nossas databases.<\/p>\n<p>Entretanto, com essa op\u00e7\u00e3o habilitada, se nossa tabela tiver mais de 500 registros (praticamente todas), as estat\u00edsticas dessa tabela s\u00f3 ser\u00e3o atualizadas quando tivermos (500 + 20% do tamanho da tabela) de altera\u00e7\u00f5es na tabela. O pior \u00e9 que isso pode acontecer no meio do dia gerando um custo no seu ambiente de produ\u00e7\u00e3o.<\/p>\n<p>No meu ambiente, tenho uma tabela que \u00e9 muito utilizada e a mesma possui 70 milh\u00f5es de registros. Se eu fosse esperar as estat\u00edsticas serem atualizadas automaticamente, desconsiderando as estat\u00edsticas de \u00edndices que s\u00e3o atualizadas por exemplo com um REBUILD, minhas estat\u00edsticas seriam atualizadas quando eu tivesse (500 + 20%*70.000.000 = 14.000.500) de altera\u00e7\u00f5es. No meu caso, isso iria demorar um tempo muito grande e querys com planos n\u00e3o \u00f3timos poderiam ser geradas.<\/p>\n<p>Para tentar minimizar esse problema, resolvi eu mesmo atualizar minhas estat\u00edsticas quando tivesse 0,5% de altera\u00e7\u00f5es na minha tabela (e n\u00e3o 20% como \u00e9 o default). Defini esse valor pois a opera\u00e7\u00e3o de UPDATE STATISTICS WITH FULLSCAN \u00e9 muito custosa e eu n\u00e3o tenho uma janela para atualizar todas as estat\u00edsticas diariamente. Com isso, essa minha tabela teria as estat\u00edsticas atualizadas quando tivesse (70.000.000 * 0.005 = 350.000) altera\u00e7\u00f5es.<\/p>\n<p>Como de madrugada j\u00e1 tenho janelas de manuten\u00e7\u00e3o de \u00edndices e dezenas de rotinas rodando, fiquei na VPN at\u00e9 \u00e0s 22:40 e rodei um UPDATE STATISTICS nesse hor\u00e1rio para analisar o impacto que teria no meu Banco de Dados que \u00e9 7&#215;24. Ent\u00e3o, defini minha janela de 22:40 \u00e0s 23:50 para executar esse procedimento.<\/p>\n<p>Em cada database que quero executar a atualiza\u00e7\u00e3o das estat\u00edsticas, criei a procedure abaixo. Em seguida fiz um job que roda diariamente \u00e0s 22:40 com um step para cada database.<\/p>\n<pre class=\"lang:tsql decode:true \">CREATE PROCEDURE [dbo].[stpAtualiza_Estatisticas]\r\nAs\r\nBEGIN\r\n\r\nSET NOCOUNT ON\r\n-- Sai da rotina quando a janela de manuten\u00e7\u00e3o \u00e9 finalizada\r\nIF GETDATE()&gt; dateadd(mi,+50,dateadd(hh,+23,cast(floor(cast(getdate()as float))as datetime)))-- hora &gt; 23:50\r\nBEGIN\r\nRETURN\r\nEND\r\n\r\nCreate table #Atualiza_Estatisticas(\r\nId_Estatistica int identity(1,1),\r\nDs_Comando varchar(4000),\r\nNr_Linha int)\r\n\r\n;WITH Tamanho_Tabelas AS (\r\nSELECT obj.name, prt.rows\r\nFROM sys.objects obj\r\nJOIN sys.indexes idx on obj.object_id= idx.object_id\r\nJOIN sys.partitions prt on obj.object_id= prt.object_id\r\nJOIN sys.allocation_units alloc on alloc.container_id= prt.partition_id\r\nWHERE obj.type= 'U' AND idx.index_id IN (0, 1)and prt.rows&gt; 1000\r\nGROUP BY obj.name, prt.rows)\r\n\r\ninsert into #Atualiza_Estatisticas(Ds_Comando,Nr_Linha)\r\nSELECT 'UPDATE STATISTICS ' + B.name+ ' ' + A.name+ ' WITH FULLSCAN', D.rows\r\nFROM sys.stats A\r\njoin sys.sysobjects B on A.object_id = B.id\r\njoin sys.sysindexes C on C.id = B.id and A.name= C.Name\r\nJOIN Tamanho_Tabelas D on\u00a0 B.name= D.Name\r\nWHERE\u00a0 C.rowmodctr &gt; 100\r\nand C.rowmodctr&gt; D.rows*.005\r\nand substring( B.name,1,3) not in ('sys','dtp')\r\nORDER BY D.rows\r\n\r\ndeclare @Loop int, @Comando nvarchar(4000)\r\nset @Loop = 1\r\n\r\nwhile exists(select top 1 null from #Atualiza_Estatisticas)\r\nbegin\r\n\r\nIF GETDATE()&gt; dateadd(mi,+50,dateadd(hh,+23,cast(floor(cast(getdate()as float))as datetime)))-- hora &gt; 23:50 am\r\nBEGIN\r\nBREAK -- Sai do loop quando acabar a janela de manuten\u00e7\u00e3o\r\nEND\r\n\r\nselect @Comando = Ds_Comando\r\nfrom #Atualiza_Estatisticas\r\nwhere Id_Estatistica = @Loop\r\n\r\nEXECUTE sp_executesql @Comando\r\n\r\ndelete from #Atualiza_Estatisticas\r\nwhere Id_Estatistica = @Loop\r\n\r\nset @Loop= @Loop + 1\r\nend\r\nEND<\/pre>\n<p>Caso algu\u00e9m tenha alguma outra sugest\u00e3o para uma rotina de atualiza\u00e7\u00e3o de estat\u00edstica, pode deixar um coment\u00e1rio.<\/p>\n<p>Lembre-se, se voc\u00ea tem uma janela grande, voc\u00ea pode atualizar todas as estat\u00edsticas diariamente que o Query Optimizer ir\u00e1 agradecer.<\/p>\n<p>&nbsp;<\/p>\n<p><b>Gostou dessa Dica?<\/b><\/p>\n<p>Curta, comente, compartilhe\u2026<\/p>\n<p>Assine meu canal no <a href=\"https:\/\/www.youtube.com\/channel\/UCeBRAO_LLrUdSrOXIywjzRA\" target=\"_blank\" rel=\"noopener\">Youtube<\/a> e curta minha p\u00e1gina no <a class=\"external-link wpel-icon-left\" href=\"https:\/\/www.facebook.com\/FabricioLimaSolucoesemBancodeDados\/\" target=\"_blank\" rel=\"nofollow external noopener noreferrer\" data-wpel-link=\"external\">Facebook<\/a> para receber Dicas de Leituras, V\u00eddeos e Eventos sobre SQL Server.<\/p>\n<p>Aprenda a criar essa e outras rotinas para administrar melhor seu SQL Server no meu <a href=\"https:\/\/www.fabriciolima.net\/cursos-online\/treinamento-tarefas-do-dia-a-dia-de-um-dba-online\/\" target=\"_blank\" rel=\"noopener\">Treinamento de Tarefas do Dia a Dia de um DBA<\/a>.<\/p>\n<p>At\u00e9 a pr\u00f3xima.<\/p>\n<p>Fabr\u00edcio Lima<\/p>\n<p>MCITP \u2013 Database Administrator<\/p>\n<p>Consultor e Instrutor SQL Server<\/p>\n<p>Trabalha com SQL Server desde 2006<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Rotina para Atualizar as Estat\u00edsticas do seu Banco de Dados<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_exactmetrics_skip_tracking":false,"_exactmetrics_sitenote_active":false,"_exactmetrics_sitenote_note":"","_exactmetrics_sitenote_category":0,"footnotes":""},"categories":[3,280],"tags":[350,63,351,357,49,33,358,360,155,359,354,356,355,40,352,353],"class_list":["post-910","post","type-post","status-publish","format-standard","hentry","category-administracao-de-bd","category-virtual-pass-br","tag-desempenho","tag-performance","tag-query-optimizer","tag-rowmodctr","tag-sql","tag-sql-server","tag-sys-allocation_units-alloc","tag-sys-indexes","tag-sys-objects","tag-sys-partitions","tag-sys-stats","tag-sys-sysindexes","tag-sys-sysobjects","tag-tuning","tag-update-statistics","tag-update-statistics-with-fullscan"],"post_mailing_queue_ids":[],"_links":{"self":[{"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/posts\/910","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/comments?post=910"}],"version-history":[{"count":3,"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/posts\/910\/revisions"}],"predecessor-version":[{"id":8553,"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/posts\/910\/revisions\/8553"}],"wp:attachment":[{"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/media?parent=910"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/categories?post=910"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/fabriciolima.net\/blog\/wp-json\/wp\/v2\/tags?post=910"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}