Hoje vou descrever uma solução que adotei durante uma visita a um cliente que estava com problemas de tamanho e performance no banco de dados. Ele utiliza Microsoft SQL Server 2005 para armazenar os dados do seu aplicativo. O problema é que precisávamos detectar tabelas que estavam grandes demais, e estavam absorvendo muitos recursos de armazenamento (tanto no servidor como no backup) e também recursos de processamento e memória. Só não confunda espaço do banco de dados com arquivo de LOG, que abordarei em um próximo artigo.
O trabalho teve várias etapas, porém vou descrever as que trouxeram maior resultado efetivo. Eu dividi o trabalho em duas partes. Primeiro identifiquei as tabelas que ocupando mais espaço. Depois, remodelei as tabelas de forma a utilizarem o espaço do banco de dados de forma mais adequada. Muitas vezes, um sistema utilizado em diversos segmentos, pode acabar tendo suas dimensões desproporcionais. Vou dar um exemplo muito simples. Você tem um sistema ERP que foi desenhado para indústrias, porém o implanta em uma distribuidora que emite 300 notas fiscais por dia, diferente do que havia sido previsto quando o sistema foi pensado para uma fábrica de médio porte. Neste exemplo, se as tabelas de notas fiscais conter campos mal dimensionados, ou relacionamentos redundantes, podem acarretar problemas de espaço e performance a longo prazo.
Neste artigo, vou abordar exclusivamente o cálculo do tamanho das tabelas. As modificações estruturais de tabelas, e demais otimizações, não vou abordar neste momento. O primeiro código que vamos analisar, é uma rotina que criei que relaciona todas as tabelas no banco de dados, calcula individualmente o espaço utilizado por cada uma e exibe no final um relatório ordenado pelas tabelas que mais utilizam espaço do banco.
sys.sp_spaceused
Este procedimento interno do SQL Server retorna informações sobre o tamanho do banco de dados, e também especificamente de tabelas passadas como parâmetro.
- exec sp_spaceused-- retorna informações do banco
- OU
- exec sp_spaceused 'cadastro' -- retorna informações da tabela
RESERVED: Espaço total reservado pelo banco de dados “para armazenamento de dados”. Por mais que sejam excluídos registros do banco, ele nunca reduz o seu tamanho (a não ser que seja feito o Shrink Database, que irá devolver ao disco o espaço UNUSED do banco).
DATA: Quantidade em KB de dados no banco de dados
INDEX_SIZE: Tamanho utilizado somente para a indexação de valores. Muitos índices em um banco podem elevar consideravelmente o tamanho do banco, é necessário estar atento.
UNUSED: Espaço que foi alocado ao banco de dados, porém não está sendo utilizado. Este espaço pode ser retomado ao disco através da ferramenta Shrink Database.
Quando passamos o nome de uma tabela como parâmetro, obtemos a mesma informação, porém os valores informados especificamente da tabela, com a diferença que temos uma coluna a mais, chamada ROWS, que retorna o número de linhas nesta tabela:
Utilizando esta ferramenta do sistema, criei o seguinte procedimento:
- create proc sp_espacotabela
- as
- /*
- Fabiano Cores 02.12.2010
- http://sqlburger.blogspot.com
- */
- declare @vname sysname
- declare @tmpTamTabela table (
- name sysname null
- , rows int null
- , reserved varchar(25) null
- , data varchar(25) null
- , index_size varchar(25) null
- , unused varchar(25) null )
- declare cp1 cursor local fast_forward read_only for
- select name
- from sysobjects
- where type = 'U'
- order by name
- open cp1
- while 1 = 1
- begin
- fetch next from cp1 into @vname
- if @@fetch_status <> 0 break
- insert into @tmpTamTabela (name, rows, reserved
- , data, index_size, unused)
- exec sp_spaceused @vname
- end
- close cp1
- deallocate cp1
- select name as 'Nome'
- , rows as 'Linhas'
- , convert(int, replace(reserved, ' KB','')) as 'Tamanho total'
- , convert(int, replace(data, ' KB',''))as 'Dados'
- , convert(int, replace(index_size, ' KB',''))as 'Index'
- , convert(int, replace(unused, ' KB',''))as 'Não utilizado'
- from @tmpTamTabela
- order by convert(int, replace(reserved, ' KB','')) desc
O código acima já está preparado para ser salvo no banco de dados, através do nome sp_espacotabela. Vamos ver agora sua execução, e o resultado apresentado:
O resultado é um relatório que retorna todas as tabelas, e os respectivos valores de consumo de tamanho em disco, conforme explicado acima. Você pode exportar esta lista para o excel, e fazer várias visões, como analisar índices x quantidade de linhas, ordenar por espaço não utilizado, etc). Observe que pode ser modificado o último SELECT do procedimento, para ordenar por outro valor. Eu optei em ordenar pelo tamanho total da tabela (RESERVED), que é o que importa nesta análise.
Após visualizar o relatório, pegamos as 10 tabelas mais inchadas do banco (de um banco com aproximadamente 2500 tabelas). Geralmente são as tabelas de LOG, notas fiscais, cupons, etc. Observamos a presença de campos tipo TEXT desnecessários (para armazenar média de 80 a 180 caracteres). Mudamos para CHAR(250), e assim por diante. Com uma pequena modificação como esta, chegamos a otimizar 3GB de uma única tabela (as imagens utilizadas aqui são somente para exemplificar).
Outras tabelas, como notas fiscais e lançamentos financeiros, fizemos uma espécie de datawarehouse, deixando na base de dados de trabalho 3 anos de histórico, os demais anos foram separados em uma base onde os relatórios consolidam estes bancos. A transição dos dados é feita automaticamente a partir de uma JOB, sem a necessidade de intervenção do usuário. O backup do período anterior fica intacto, armazenado em mídia separada. O backup feito diariamente passou a ser dos últimos 3 anos.
Todas estas modificações trouxeram grandes benefícios, como otimização dos backups, mais velocidade em processos críticos do sistema (faturamento, log), banco de dados mais enxuto, sem alocar grandes espaços desnecessários, e assim por diante.
Resultados
No final, aplicando as técnicas aqui descritas, e outras manutenções, o banco de dados de produção, que estava com 13,5GB de tamanho, ficou com modestos 1,8GB. O backup, que é totalmente automatizado, estava levando mais de 5 horas para ser realizado, pois o banco compactado ficava com 3,0GB. Levava 1 hora para compactar, e 4 horas para transmitir. E se houvessem quedas de internet durante a transmissão, esta tinha que ser feita manualmente. Hoje, o arquivo de backup compactado está com 122mb, leva 2 minutos para ser gerado e 20 minutos para ser transmitido.
Muito bom, vai ser muito util.
ResponderExcluirEstou com uma base de dados com um tamanho monstruoso e preciso esvaziar algumas tabelas.
Agora ficou mais facil, pois sei quais são elas ;)
Essa dica foi muito boa, obrigado!
ResponderExcluirParabéns, graças a seu comando consegui localizar vários erros de modelagem em um sistema ERP que é uma tartaruga.
ResponderExcluirParabéns, graças a seu comando consegui localizar vários erros de modelagem em um sistema ERP que é uma tartaruga.
ResponderExcluirComo eu Faço para consultar o tamanho das tabelas de todos os meus bancos em uma instancia?
ResponderExcluirVocê me sugeriu um bom artigo. Hoje devo colocá-lo no ar... por favor, acompanhe o blog que eu irei postar uma solução bem bacana...
ExcluirSegue o artigo, qualquer dúvida avisa aí:
Excluirhttp://sqlburger.blogspot.com.br/2013/01/tamanho-de-todas-as-tabelas-de-todos-os.html
http://sqlburger.blogspot.com.br/2013/01/tamanho-de-todas-as-tabelas-de-todos-os.html
ExcluirE no caso de uma tabela particionada?
ResponderExcluirComo contar separadamente as partições.
Luiz, vou pesquisar e retorno com uma resposta... não havia pensado nisto.
ExcluirMuito bom mesmo o artigo parabéns e muito obrigado.
ResponderExcluirtttttttttttttttttttttooooooooooooooooooooooppppppppppppppppppppp
ResponderExcluirTentei dar o commando:
ResponderExcluirexec sp_spaceused px1.[/XNFE/B2BSTATUS]
Error:
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '.'.
Parabéns, ótimo artigo!!
ResponderExcluir