Mostrando postagens com marcador Artigo. Mostrar todas as postagens
Mostrando postagens com marcador Artigo. Mostrar todas as postagens

sexta-feira, 2 de março de 2012

Otimizando o Data Cache

Bom dia pessoal.

No dia 01/02/2012 eu publiquei uma pesquisa no meu blog para analisarmos como está o desperdício no data cache do seu SQL Server (http://luticm.blogspot.com/2012/01/pesquisa-desperdicio-no-data-cache.html).

Como vocês podem ver pelas repostas, é usual termos um desperdício de 8% a 15%, o que isso significa? Se você tem um data cache com 30 GB de tamanho, então algo entre 2,4GB e 4,5GB está sendo desperdiçado.

É claro que não tenho ilusão de que 100% do data cache estará ocupado, pelo contrário, temos fragmentação normal dos índices, níveis não folha e outras páginas de controle usualmente possuem espaço livre, então parte desse espaço em memória vai ser desperdiçado sim! Mas você como DBA deve cuidar para que o desperdício seja o menor possível. Como?

  • Modelando corretamente seu banco de dados
  • Usando outros recursos, como compressão de dados (cuidado sempre com os trade-offs).
  • Garantindo a manutenção dos seus índices
  • Tomando muito cuidado com thresholds globais    Fillfactor? PADIndex? Fragmentação para reorganize e Rebuild?    Na boa, quem já fez treinamento comigo sabe que sou bem ácido em relação a essas recomendações universalmente aceitas, usualmente elas podem te prejudicar muito.

Todos vocês podem ver o que os outros publicaram e tirar suas próprias conclusões, então dentro do que foi mostrado eu gostaria de propor uma nova verificação para todos os ambientes: tentar minimizar o desperdício do data cache!

Qual o threshold? (Opa, acabei de falar mal de thresholds globais! Shame on me :-))
Se o seu negócio permitir (normalmente sim), vamos com uma meta ambiciosa: manter o desperdício do data cache sempre abaixo de 10%.

E claro que nem sempre a coisa é simples e muitos detalhes podem tornar a vida do DBA mais complexa (e divertida, porque não?). Imagine o seguinte... Seu índice apresenta fragmentação interna de 3% mas o desperdício dela no data cache para este objeto é de 50%!

Sim, isso pode acontecer com você, é o que eu chamo de fragmentação de um ramo da árvore (B-tree+), principalmente quando suas tabelas começam a crescer demais e uma fragmentação em um ramo mais utilizado pode passar despercebida, quando analisado todo o índice.

Esse seria um post longo, mas acabei escolhendo por publicar o artigo no SimpleTalk (http://www.simple-talk.com/sql/database-administration/no-significant-fragmentation-look-closer%E2%80%A6/) para ver se tinha aceitação também lá fora.

Então você somente pode considerar que leu esse post depois de ler o artigo inteiro e deixar lá seu comentário e avaliação, seja boa ou ruim.


[]s
Luciano Caixeta Moreira - {Luti}
luciano.moreira@srnimbus.com.br
www.twitter.com/luticm
www.srnimbus.com.br

sexta-feira, 8 de julho de 2011

[Artigo] O caso dos snapshots e data cache thrashing

Segue mais um artigo!
Data cache e database snapshots! Gostei bastante de escrevê-lo.
Oriundo de uma dúvida na DL do SQLServerDF, já estou começando a escrever outro post sobre Database Snapshots. Legal ou não?

https://skydrive.live.com/?cid=e145f7753042d628&sc=documents&uc=1&id=E145F7753042D628%211068

PS: já que esse artigo surgiu de uma última conversa com o Luan Moreno como funcionário da Nimbus, que agora está ajudando outra empresa com suas habilidades de DBA, fica aqui o meu obrigado para esse amigo e que possamos ter muitas outras conversas!

Sucesso Luan! Fica rico e depois volta para a Nimbus.

[]s
Luciano Caixeta Moreira - {Luti}
luciano.moreira@srnimbus.com.br
www.twitter.com/luticm
www.srnimbus.com.br

quinta-feira, 14 de abril de 2011

ADO.NET SqlParameter vs. Plan Cache

Oi pessoal, escrevi um novo artigo sobre o uso efetivo do SqlParameter e seu efeito no plan cache do SQL Server. Depois eu penso em atualizar o blog com o texto (sim, não tenho muita paciência para formatação), mas publiquei o PDF no skydrive.



Espero que vocês gostem...

[]s
Luciano Caixeta Moreira - {Luti}
luciano.moreira@srnimbus.com.br
www.twitter.com/luticm
http://www.srnimbus.com.br/

terça-feira, 23 de março de 2010

[Artigo] Herança no EF4 e Identity no SSDL

Este artigo descreve brevemente o uso de herança (type per hierarchy) no Entity Framework 4.0, mas destaca um problema que enfrentei com o modelo de entidades quando estava fazendo o mapeamento a partir do banco de dados.
No fim o problema talvez poderá ser resolvido com o RTM do Visual Studio 2010 ou continuar em aberto (existe uma entrada no connect), então pode ser que você precise de uma mãozinha sobre o assunto.

No artigo eu também comento sobre as exceções “A member named cannot be defined in class . It is defined in ancestor class ” e “A value shared across entities or associations is generated in more than one location. Check that mapping does not split an EntityKey to multiple store-generated columns”.

Parti do pressuposto que você já conhece um pouco do Entity Framework, caso contrário, eu já gravei alguns webcasts sobre o assunto e um artigo que escrevi sobre as novidades do EF 4.0 deve sair qualquer dia desses em uma publicação nacional.

Quer ver o artigo completo? Baixe-o aqui.



[]s
Luciano Caixeta Moreira - {Luti}
Chief Innovation Officer
Sr. Nimbus Serviços em Tecnologia Ltda
luciano.moreira@srnimbus.com.br
www.twitter.com/luticm

terça-feira, 23 de fevereiro de 2010

Artigo: Como o Query Optimizer utiliza (ou não) constraints unique e filtered indexes

Bom dia pessoal.

Aproveitando o gancho do último post, escrevi hoje um artigo com duas intenções:


  1. Mostrar como o query optimizer do SQL Server se beneficia de constraints unique
  2. Mostrar uma característica do optimizer com filtered indexes que me parece um bug
Como o artigo ficou grande e acho que a leitura será mais agradável com a formatação do PDF, não vou colocar ele inteiro como um post, deixo somente o link para download do PDF.

Como o Query Optimizer utiliza (ou não) constraints unique e filtered indexes




Espero que vocês gostem e deixem aqui seus comentários...

[]s
Luciano Caixeta Moreira - {Luti}
Chief Innovation Officer
Sr. Nimbus Serviços em Tecnologia Ltda
luciano.moreira@srnimbus.com.br
www.twitter.com/luticm

quinta-feira, 4 de fevereiro de 2010

Compressão de registro no SQL Server 2008

(Para melhor visualização, baixe AQUI o pdf.)

Compressão de dados não é lá novidade, então vamos brincar de internals...

Uma das novas funcionalidades do SQL Server 2008 é a possibilidade de compactar os registros dentro de uma página, sendo possíveis duas abordagens: registro e página. A compressão de registro transforma as colunas de tamanho fixo (INT, CHAR, ROWVERSION, etc.) em tamanho variável, e a compressão de página, além de aplicar a compressão de registro, irá fazer a compressão de prefixo e dicionário.

A compressão de dados é importante para diminuir a utilização do espaço em disco (você ganha os benefícios colaterais disso), e por outro aspecto muito importante, que às vezes fica relegado a segundo plano. Potencialmente a compressão de dados vai melhorar a eficiência da cache de dados, pois se caberão mais registros em uma página de 8K, então mais registros serão colocados no mesmo espaço em memória e a probabilidade do acerto em cache acontecer também aumenta. Lindo, não?

Pensando um pouco no assunto, seria extremamente ineficiente se o SQL Server 2008 utilizasse o mesmo mecanismo do tipo VARCHAR, pois ele já gasta de largada mais dois bytes em cada registro (valor exato por simplificação). Se fosse um inteiro (4 bytes) acabaríamos somente tendo ganho quando armazenássemos um valor menor que 127 (1 byte), pois depois disso o overhead deixaria o campo variável com o mesmo tamanho da coluna fixa (2 + 2 = 4) e a partir de 3 bytes a compressão iria perder espaço.

Como claramente o mecanismo tem que outro (VARDECIMAL é assim), vamos analisar um pouco a compressão de registro nesse artigo, mais especificamente CD (column descriptor) e a short data region. Primeiramente execute o script abaixo para criar uma tabelinha boba que servirá de exemplo.

Nota: número das páginas, local, distribuição, entre outros, podem variar de exemplo para exemplo, então siga o raciocínio.

Script 01: Tabela para teste

USE Inside
go

IF OBJECT_ID('CompressaoDados') IS NOT NULL
DROP TABLE CompressaoDados
go

CREATE TABLE CompressaoDados
(Codigo BIGINT IDENTITY PRIMARY KEY NOT NULL,
Nome VARCHAR(100) NOT NULL,
Idade BIGINT NOT NULL,
SeloTempo ROWVERSION NOT NULL)
GO

DECLARE @I INT
SET @I = 1
WHILE (@I <>
BEGIN
INSERT INTO CompressaoDados (Nome, Idade) VALUES (CAST(NEWID() AS VARCHAR(40)) + CAST(NEWID() AS VARCHAR(40)), @I % 100)
SET @I = @I + 1
END
go

Com a tabela criada, aproveitamos para olhar os dados e também algumas informações das unidades de alocação (script 02). Aqui podemos notar uma tabela com 473 páginas de dados, sendo a primeira na posição 22 (0x00000016).

Script 02: unidades de alocação

SELECT TOP 100 * FROM CompressaoDados
go

SELECT AU.*
FROM sys.system_internals_allocation_units AS AU
INNER JOIN SYS.Partitions AS P
ON AU.Container_id = P.Partition_id
WHERE Object_ID = object_id('CompressaoDados')
go

A página atual mantém os registros no formato que você já conhece desde o SQL Server 7.0, o FixedVar, conforme podemos notar através do DBCC PAGE (figura 01). Aqui podemos ver algumas coisas importantes, no cabeçalho temos a quantidade de registros por página (m_SlotCnt = 74), o tamanho do registro em 107 bytes e o espaço sendo desperdiçado com o tamanho fixo dos campos bigint e rowversion.



(Figura 01)

Com base no que nós discutimos até agora, pergunto: Essa página irá se beneficiar com compressão de registro? E de página?

R: registro sim, pois temos espaço sendo desperdiçado em colunas de tamanho variável. Já de página, muito provavelmente não. Consegue ver o motivo? Espero que sim, em outro post ou comentário eu volto a esse assunto.

Vamos habilitar compressão de registro e ver o resultado da compressão através da consulta 02, aproveitando para executar um DBCC PAGE na página 648 (0x00000288). Vemos que a tabela ocupa agora 381 páginas ao invés das 473 originais, o número de registros por página aumentou para 93 (figura 02 - que beleza!), o tamanho do primeiro registro é de 85 bytes (contra os antigos 107) e os registros na página estão ocupando pouco espaço (nada de muitos zeros no meio). Viu?


Script 03: compressão e análise

ALTER TABLE CompressaoDados
REBUILD WITH (DATA_COMPRESSION = ROW);
GO

SELECT AU.*
FROM sys.system_internals_allocation_units AS AU
INNER JOIN SYS.Partitions AS P
ON AU.Container_id = P.Partition_id
WHERE Object_ID = object_id('CompressaoDados')
go

DBCC PAGE (8, 1, 648, 3)


(Figura 02)

É interessante notar que agora o formato do registro mudou e cada registro possui um cabeçalho, column descriptor, que fala o tamanho de cada campo (4 bits por campo), uma short data region (para colunas de até 8 bytes) e um long data region (maiores de 8 bytes). No nosso caso não precisamos de ponteiros de 1byte para os clusters de short data, que são compostos por 30 colunas, pois somente temos quatro colunas (o que cabe em um cluster).
No início do registro temos a informação 2104a232, quebrando-a em bytes temos...
21 (0010 e 0001) = header - Significa registro no formato CD, primário e coluna long.
04 = Número de colunas nesse registro.
A2 = Primeira coluna têm um byte, segunda coluna é longa (mais de 8 bytes)
32 = Terceira coluna têm um byte, quarta coluna têm dois bytes.

Então esse registro pode compactar bem as colunas, pois somente estamos com valores pequenos, mas o mesmo se manteria em todos os registros? Claro que não, vamos navegar na cadeia de páginas para a próxima de nosso índice e achar os registros de código 127 e 128. O DBCC Page da página 649 (m_nextPage) mostra claramente quando 1 byte não é mais suficiente para armazenar o código, pulando para 2 bytes a partir desse momento.



(Figura 03)

Aqui vemos o registro passando de 85 para 86 bytes de tamanho e o espaço necessário para a primeira coluna salta de um para dois bytes. Nos quatro bits de descrição vemos a mudança de 2 para 3 (nota: o slotcnt saiu de 93 para 92, como esperado). Interessante, não? Isso vai acontecer novamente para a coluna Código? Sim, quando chegarmos ao 32768 veremos outra alteração no tamanho necessário para o campo código.

Quer ver essa mudança? Então aproveite uma nova função no SQL Server para ver o local físico de cada um dos seus registros. Sys.fn_PhysLocFormatter(%%PHYSLOC%%), encontre o 32768 e DBCC PAGE nele! Exemplo: (1:1060:14) 32768 => arquivo 1, página 1060, slot 14.

SELECT SYS.fn_PhysLocFormatter(%%PHYSLOC%%) AS RID, Codigo
FROM CompressaoDados
WHERE Codigo between 32700 and 32800

Espero que você possa ter entendido um pouco da compressão de registros e consiga fazer melhores análises críticas sobre o uso do recurso no SQL Server 2008. Ainda existem mais detalhes sobre a formação do CD, short data com mais colunas e long data, além da compressão de página que pretendo abordar em um outro artigo.
O SQL Server 2008 R2 trás novidades na compressão UNICODE, o jeito é brincar com ele também para ver as diferenças.

O script está disponível no endereço:
http://cid-e145f7753042d628.skydrive.live.com/self.aspx/Public/BlogPosts/20100204^_RowCompressionInternals.zip

[]s
Luciano Caixeta Moreira - {Luti}
Chief Innovation Officer
Sr. Nimbus Serviços em Tecnologia Ltda
luciano.moreira@srnimbus.com.br
www.twitter.com/luticm