Update Statistics quando vai acontecer?


Como todo o bom DBA você tem um plano de manutenção configurado para seu ambiente SQL.

Você costuma fazer rebuild/reindex, update statistics, backup, garante que o HA está funcionado,,,

Você provavelmente deve ter a opção de “auto update statistics” habilitada em suas bases e sabe como ela funciona,,, certo?

Bom,,, no bom e velho “by the book” o “auto update statistics” funciona assim:

  • Em uma tabela permanente:
    1. se a tabela não tem linhas, as estatísticas são atualizadas quando uma alteração for executada na tabela
    2. se o número de linhas for menor que 500, as estatísticas são atualizadas a cada 500 alterações na tabela
    3. se o número de linhas for superior a 500, as estatísticas são atualizadas a cada 20% + 500 alterações na tabela
  • Tabelas temporárias:
    1. se a tabela não tem linhas, as estatísticas são atualizadas quando uma alteração for executada na tabela
    2. se a tabela possui menos de 6 linhas, as estatísticas são atualizadas a cada 6 alterações na tabela
    3. se o número de linhas for menor que 500, as estatísticas são atualizadas a cada 500 alterações na tabela
    4. se o número de linhas for superior a 500, as estatísticas são atualizadas a cada 20% + 500 alterações na tabela
  • Tabelas variáveis (ficou feio,,, eu sei)
    1. Não existem estatísticas em variáveis de tabela (agora ficou menos pior)

Até aí nenhuma novidade certo? certo….

Com esse conceito em mente,,, imagine que você tem umas 40 tabelas com alguns 14.000.000 de registros cada, umas outras 200 tabelas com uns 30.000 registros cada,,, você sabe quem vai ser a próxima vítima do malévolo processo de “auto update statistics” ?

Acho que muito poucas pessoas tem a opção de “auto update statistics asynchronously” habilitada, então alguma query vai sofrer com a espera da atualização de uma estatística e alguém vai achar que é lentidão no sistema… Smiley de boca aberta

Então como monitorar a quantidade de alterações de uma tabela pra saber se ela está chegando aos malvados 20% +500 ?

Tá lá uma query:

/*SQL 2005*/ 
SELECT SO.NAME AS tableName, SC.NAME AS columnName, SSC.*, SSR.* FROM sys.sysrowsetcolumns SSC 
INNER JOIN sys.sysrowsets SSR ON SSC.rowsetID = SSR.rowsetID 
INNER JOIN sys.sysobjects SO ON SSR.idmajor = SO.id 
INNER JOIN sys.syscolumns SC on SSR.idmajor = SC.id AND SSC.rowsetcolid = SC.colid 
WHERE SO.xtype = 'U' 
ORDER BY so.name, sc.colid 
/*SQL 2008*/  
SELECT SO.NAME AS tableName, SC.NAME AS columnName, SSC.*, SSR.* FROM sys.sysrscols SSC  
INNER JOIN sys.sysrowsets SSR ON SSC.rowsetID = SSR.rowsetID  
INNER JOIN sys.sysobjects SO ON SSR.idmajor = SO.id  
INNER JOIN sys.syscolumns SC on SSR.idmajor = SC.id AND SSC.rscolid = SC.colid  
WHERE SO.xtype = 'U'  
ORDER BY so.name, sc.colid

Não conseguiu executar??????? hehehehe Smiley de boca aberta

Precisa habilitar o DAC, as tabelas sysrscols, sysrowsetcolumns e sysrowsets só podem ser acessadas pelo DAC.

Outra coisa, não esqueça de mudar a base,,,

Mas até ai, o que tem de interessante no resultado?

O nome da tabela já sabemos, qual a coluna? grande coisa,,, o que importa é a coluna rcmodified e a coluna rcrows, quantidade de modificações e contagem de linhas respectivamente.

Agora sim,,, já começamos a ter alguma coisa legal…. mas tem como melhorar? sabemos as tabelas e as colunas… temos como saber quais as estatísticas que vão ser impactadas pela atualização? Claro…

/*SQL 2005*/
SELECT SO.NAME AS tableName, COL_NAME(sc.object_id, sc.column_id) AS columnName, A.name as stats_name, SSC.*, SSR.* FROM sys.sysrowsetcolumns SSC 
INNER JOIN sys.sysrowsets SSR ON SSC.rowsetID = SSR.rowsetID 
INNER JOIN sys.sysobjects SO ON SSR.idmajor = SO.id 
INNER JOIN sys.stats_columns SC on SSR.idmajor = SC.object_id AND SSC.rowsetcolid = SC.column_id 
INNER JOIN sys.stats as A ON A.object_id = SO.id 
WHERE SO.xtype = 'U' 
ORDER BY so.name, sc.column_id 
/*SQL 2008*/ 
SELECT SO.NAME AS tableName, COL_NAME(sc.object_id, sc.column_id) AS columnName, A.name as stats_name, SSC.*, SSR.* FROM sys.sysrscols SSC 
INNER JOIN sys.sysrowsets SSR ON SSC.rowsetID = SSR.rowsetID 
INNER JOIN sys.sysobjects SO ON SSR.idmajor = SO.id 
INNER JOIN sys.stats_columns SC on SSR.idmajor = SC.object_id AND SSC.rscolid = SC.column_id 
INNER JOIN sys.stats as A ON A.object_id = SO.id 
WHERE SO.xtype = 'U' 
ORDER BY so.name, sc.column_id 

Isso é uma informação interessante,,, por que precisamos disso? Imagine uma tabela com alguns milhões de linhas, se a atualização de estatísticas ocorre apenas a cada 20%+500 modificações é bem provável que o intervalo entre uma atualização e a outra seja um pouco grande…

Aí você pergunta: mas eu faço rebuild dos meus índices com uma boa frequência e eu sei que, com esse processo, ele já faz a atualização das estatísticas, o que eu ganho com isso?

Ai eu respondo: Você pode ter estatísticas que são criadas automaticamente,,, lembra da opção do “auto create statistics” que costuma estar habilitada por padrão? da uma olhada na sua tabela, veja se existem estatísticas começando com _WA então,,, o rebuild de índices vai atualizas as estatísticas que ele utiliza e não todas as da tabela…

bom,,,, é isso,,, bom proveito…

TableDiff


Imagine a situação do post Corrompendo um Banco SQLmas na vida real,,,

Você chega um belo dia na empresa e, lê nos seus emails que, o SQL apresentou falha na estrutura de dados e algumas páginas de dados podem ter sido corrompidas,,,

Como um bom DBA, você corre para ver se o backup da noite foi feito, se os backups de transaction log também estão sendo feitos e descobre que sim,,,, todos os arquivos necessários para restaurar o banco estão lá,,,

Legal,,, mas,,, e agora? dependendo da utilização do banco você pode restaurar o backup da madrugada, os de log até o horário do problema e dali pra frente o que der pra fazer…

Em outros casos,,, você não pode se dar ao luxo de perder informação,,,,

Uma das formas seria executar o restore do banco em outro lugar, ou na mesma instância mas com outro nome, executar o checkdb e remover a página com problema e trazer a diferença dos dados,,, até aqui nada tão complicado,,, tirando o fato de se a tabela for muito grande, ou muito complexa e a query para mostrar essa diferença for muito complicado…

Para ajudar a resolver esse problema, o SQL possui uma ferramenta bem interessante chamada TableDiff.

O conceito dela é bem simples: Instância de origem, base de origem, tabela de origem, Instância de destino, base de destino, tabela de destino e o que você quer fazer…

Ex:

"C:\Program Files\Microsoft SQL Server\90\COM\tablediff.exe" -sourceserver MyServer1
                                                             -sourcedatabase MyDatabase1
                                                             -sourcetable MyTable1
                                                             -destinationserver MyServer1
                                                             -destinationdatabase MyDatabase1
                                                             -destinationtable MyTable2
                                                             -et DiffsTable

 

Nesse outro exemplo ele gera um arquivo com INSER/UPDATE/DELETE

"C:\Program Files\Microsoft SQL Server\90\COM\tablediff.exe" -sourceserver MyServer1
                                                             -sourcedatabase MyDatabase1
                                                             -sourcetable MyTable1
                                                             -destinationserver MyServer1
                                                             -destinationdatabase MyDatabase1
                                                             -destinationtable MyTable2
                                                             -et DiffsTable
                                                             -f d:\MyTable1_MyTable2_diff.sql

 

Simples certo? em teoria não é muito complicado…

Da pra deixar mais fácil? sim,,, com certeza…

O Sr. Mladen Prajdic (Blog | Twitter) desenvolveu uma interface bem interessante para ajudar na utilização do executável…

O link para download pode ser encontrado no post aqui, ou diretamente aqui.

O aplicativo é bem simples de usar, o ponto de atenção é que você precisa indicar onde está o executável do TableDiff.exe.

tablediffgui

Ele é bem auto-explicativo, pequeno e o principal,,, é de graça !!!

Vale gastar uns minutos para aprender a usar ele, vai que em um dia de emergência você precisa de uma ajuda rápida para solucionar um problema, ou ver a diferenças nas tabelas do seu logshipping….

Localizando tabelas não usadas


Este script irá retornar uma lista de tabelas do banco que, desde o último restart do SQL, não tiveram um SELECT executado contra elas. Isto pode ser usado para determinar se a tabela é usada ou não.
ATENÇÃO: As estatísticas do SQL são apagadas toda a vez que o serviço do SQL é reiniciado. Então, não é porque o script esta informando que a tabela não teve uso que ela não é importante, ela apenas não teve uso desde o último restart. Então não saia apagando tabelas ao seu bel prazer, vai que uma delas é usada pelo sistema fiscal apenas a vez por mês e você reinicia o SQL a cada Windows Update, você sempre vai ver essa tabela com esse script.

WITH LastActivity (ObjectID, LastAction) AS
(
SELECT object_id AS TableName,
             last_user_seek as LastAction
     FROM sys.dm_db_index_usage_stats u
WHERE database_id = db_id(db_name())
UNION
SELECT object_id AS TableName,
             last_user_scan as LastAction Continuar lendo