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…

Pressão de processador?


A algumas semanas atrás eu estava ajudando um cliente a localizar problemas de lentidão no ambiente dele. Não havia um ponto exato, não era sempre na mesma aplicação, muitas vezes nem a mesma unidade, isso ajudava muito na localização do problema,,, Smiley triste

Um dos analistas de desenvolvimento me indagou se o servidor de SQL estava sofrendo com problemas de processador,,, em alguns momentos o servidor apresentava alguns picos em um dos núcleos mas nada muito longo muito menos alarmante.

proc

Com a query abaixo, mostrei que não havia problemas de processamento,,, pelo menos naquele momento…

 Select signal_wait_time_ms=sum(signal_wait_time_ms)<br>,'%signal (cpu) waits' = cast(100.0 * sum(signal_wait_time_ms) / sum (wait_time_ms) as numeric(20,2))<br>,resource_wait_time_ms=sum(wait_time_ms - signal_wait_time_ms)<br>,'%resource waits'= cast(100.0 * sum(wait_time_ms - signal_wait_time_ms) / sum (wait_time_ms) as numeric(20,2))<br>From sys.dm_os_wait_stats 

O resultado é o seguinte:

proc1

Agora vem a pergunta: Legal, mas idaí?

O que nos interessa nesse resultado é o %signal (cpu) waits e o %resource waits.

A matemática é bem simples: quanto mais %recouce waits e menos %signal (cpu) waits melhor, quer dizer que, nesse momento não está havendo problemas de pressão com processador, não quer dizer que daqui a 1 segundo não comece a ter, mas no momento da execução dessa query não havia problema.

English version

A few weeks ago i was helping a client to find a slow problem on his environment. Don´t had a exact point, not always the same apllication, even the same place and this help a lot to find the problem.

One of the developers ask me if the SQL Server had problems with processos pressure,,, in a few moments on the day the server show a top processes in one of the cores, but was not the problem.

With the query below i show that we don´t have any problem with the processor, in that moment…

 Select signal_wait_time_ms=sum(signal_wait_time_ms)<br>,'%signal (cpu) waits' = cast(100.0 * sum(signal_wait_time_ms) / sum (wait_time_ms) as numeric(20,2))<br>,resource_wait_time_ms=sum(wait_time_ms - signal_wait_time_ms)<br>,'%resource waits'= cast(100.0 * sum(wait_time_ms - signal_wait_time_ms) / sum (wait_time_ms) as numeric(20,2))<br>From sys.dm_os_wait_stats 

The result was:

proc1

And then comes the question: Cool, but WTF?

The important is %signal (cpu) waits and %resource waits.

The mathematic is simple: more %recouce waits and lass %signal (cpu) waits is better, in that moment the server don´t have processos pressure.

Sorry about the poor English, i´ll fix at night.