Como calcular a massa de dados no SQL Server?

Fala galera, semana passada precisei fazer uma apresentação para o Comitê de IT do cliente que estou atuando. Essa apresentação tinha diversos pontos positivos de utilização de uma certa solução, e pra provar precisei mostrar alguns números. Foi necessário calcular a massa de dados (em tamanho) das informações que estavam sendo apresentadas e sincronizadas.

Para ficar claro o que precisamos fazer, vou tentar explicar superficialmente: O trabalho é pra sincronizar dados de uma aplicação OnLine (Web) com uma OffLine (Win) e o usuário trabalhar desconectado. A solução existente (não podemos mudar) realiza dois sincronismos: um na hora que o sistema é aberto a primeira vez e o segundo de tempos em tempos quando o usuário está conectado à Internet.

Bom, o pessoal do Comitê precisava saber o tamanho dos dados que seriam sincronizados no primeiro e no segundo momento. Então, criei um script e rodei em produção para me devolver essas informações. Por questões de sigilo dos dados, vou adaptar o script para rodar em cima do AdventureWorks e mostrar o resultado pra vocês. Com os dados reais fiz a consulta de 2009, mas pra esse exemplo utilizei 2003.

Gostaria de agradecer o Laerte Junior por me ajudar em um pedaço do script, eu mandei o código para ele e prontamente ele me respondeu com o pedaço que estava dando erro, corrigido! Se não fosse ele, eu teria perdido mais algumas horas. Tks brother!

Caso alguém não tenha o AdventureWorks, pode baixar gratuitamente.

SQL Server 2008: http://msftdbprodsamples.codeplex.com/releases/view/37109

SQL Server 2008 R2: http://msftdbprodsamples.codeplex.com/releases/view/24854

O script é esse:

SET NOCOUNT ON

/* Máximo de bytes do primeiro sincronismo */
print('*********************************************************')
print('Máximo de bytes do primeiro sincronismo [VENDAS]')

CREATE TABLE #TB_MASSA_TOTAL
(NAME varchar(100) null
,rows int
,reserved varchar(10)
,data varchar(10)
,index_size varchar(10)
,unused varchar(10))

CREATE TABLE #TB_EXECS
(CODIGO varchar(100))

INSERT INTO #TB_EXECS (codigo)
SELECT ' EXEC sp_spaceused N''Sales.' + name + ''';' from sysobjects where name like '%Sales%' and xtype = 'U'

DECLARE @SCRIPT VARCHAR(100)
DECLARE cr_cursor CURSOR
FOR SELECT codigo FROM #TB_EXECS
OPEN cr_cursor
FETCH NEXT FROM cr_cursor INTO @SCRIPT
WHILE @@FETCH_STATUS = 0
    BEGIN
        INSERT INTO #TB_MASSA_TOTAL EXEC (@script)
        FETCH NEXT FROM cr_cursor INTO @script
    END

CLOSE cr_cursor
DEALLOCATE cr_cursor

SELECT (SUM(CONVERT(INT, REPLACE(reserved,' KB',''))) + SUM(CONVERT(INT, REPLACE(index_size,' KB',''))) ) / 1024 [MB]
      ,(SUM(CONVERT(INT, REPLACE(reserved,' KB',''))) + SUM(CONVERT(INT, REPLACE(index_size,' KB',''))) ) [KB]
      ,(SUM(CONVERT(INT, rows))) [LINHAS]
FROM #TB_MASSA_TOTAL

/* Qtd de Vendas em 2009 */
print('*********************************************************')
print('Qtd de Vendas em 2003')
select count(0) [Qtd]
from Sales.SalesOrderDetail s inner join
     Sales.SalesOrderHeader h
     on s.SalesOrderID = h.SalesOrderID
where h.OrderDate between '2003-01-01' and '2003-12-31'

/* Qtd de CPRs criadas em 2009 separadas por mês */
print('*********************************************************')
print('Qtd de Vendas em 2003 separadas por mês')
select case month(h.OrderDate)
        when 1 then '01 (Jan)'
        when 2 then '02 (Fev)'
        when 3 then '03 (Mar)'
        when 4 then '04 (Abr)'
        when 5 then '05 (Mai)'
        when 6 then '06 (Jun)'
        when 7 then '07 (Jul)'
        when 8 then '08 (Ago)'
        when 9 then '09 (Set)'
        when 10 then '10 (Out)'
        when 11 then '11 (Nov)'
        when 12 then '12 (Dez)' end [Mês], count(*) Qtd
from Sales.SalesOrderDetail s inner join
     Sales.SalesOrderHeader h
     on s.SalesOrderID = h.SalesOrderID
where h.OrderDate between '2003-01-01' and '2003-12-31'
group by month(h.OrderDate)
order by Mês

/* Máximo de qtd de Bytes (por linha) na tabela eCPR_CPR */
print('*********************************************************')
print('Máximo de qtd de Bytes (por linha) na tabela de Detalhes')
select (sum(c.length) / 8) [Bytes]
from syscolumns c
    inner join sysobjects o
on c.id = o.id
where o.name = 'SalesOrderDetail'

print('*********************************************************')
print('Máximo de qtd de Bytes (por linha) na tabela de Cabeçalho')
select (sum(c.length) / 8) [Bytes]
from syscolumns c
    inner join sysobjects o
on c.id = o.id
where o.name = 'SalesOrderHeader'

DROP TABLE #TB_MASSA_TOTAL
DROP TABLE #TB_EXECS

SET NOCOUNT OFF

e o resultado apresentado é esse:

*********************************************************
Máximo de bytes do primeiro sincronismo [VENDAS]
MB          KB          LINHAS
----------- ----------- -----------
32          32848       180675

*********************************************************
Qtd de Vendas em 2003
Qtd
-----------
51237

*********************************************************
Qtd de Vendas em 2003 separadas por mês
Mês      Qtd
-------- -----------
01 (Jan) 1227
02 (Fev) 1936
03 (Mar) 1487
04 (Abr) 1743
05 (Mai) 2641
06 (Jun) 2019
07 (Jul) 3600
08 (Ago) 7585
09 (Set) 7653
10 (Out) 5959
11 (Nov) 7085
12 (Dez) 8302

*********************************************************
Máximo de qtd de Bytes (por linha) na tabela de Detalhes
Bytes
-----------
15

*********************************************************
Máximo de qtd de Bytes (por linha) na tabela de Cabeçalho
Bytes
-----------
65

Em posse dessas informações consegui apresentar os dados necessários para o comitê de IT do cliente que ficou impressionado com o “detalhe” das informações. Eles esperavam algo superficial, e com o resultado apresentado, ficaram super satisfeitos e contentes (e ganhamos pontos para fechar mais projetos).

Gostaria de ver nos comentários de vocês outras formas que encontraram para chegar a um resultado destes.

Comentários

pingback
topsy.com
11/5/2010 11:13:38 #

Pingback from topsy.com

Twitter Trackbacks for
        
        Think Think .Net | Como calcular a massa de dados no SQL Server?
        [diegonogare.net]
        on Topsy.com

Fernando H. Rosa
Fernando H. Rosa
11/5/2010 17:53:16 #

Legal, foi de grande ajuda.
Estive procurando algo que fizesse isso mesmo.

Thiago Zavaschi
Thiago Zavaschi
11/5/2010 21:37:45 #

Grande Nogare, beleza?!
Bom.. vamos lá!
Vou postar algumas considerações Tong
Primeiramente eu particularmente não costumo gostar de soluções que sejam baseadas em cursores, MAS neste caso como será uma execução de uma tarefa administrativa que NÃO ocorre regularmente podemos dizer que não há problemas. Gosto de enfatizar pois as pessoas precisam entender bem o porque que algumas horas falam que tudo bem usar e outras vezes não.
Só pra tornar o cometário mais completo vou explicar o principal motivo de evitar o uso dos cursores (eu sei que tu sabe Diego, mas é para os seus leitores heheh):
O SQL Server trabalha excepcionalmente quando se trata de operações ditas set-based (baseadas em conjuntos). Cursores são operações row-based (baseadas em linhas). Ao invés de acontecer um processamento único e otimizado sobre conjunto, o cursor força uma tratativa linha a linha, o que em 95% dos casos é prejudicial.
Posto isso (sempre quis falar isso ehhehe) vou compartilhar o script que uso (originário do SQLDBATips para verificar tamanho de tabelas (não é beeem a mesma coisa, mas acho que pode agregar valor ao post!), também utiliza cursor:

DECLARE @hr int
DECLARE @fso int
DECLARE @drive char(1)
DECLARE @odrive int
DECLARE @TotalSize varchar(20)
DECLARE @MB bigint ; SET @MB = 1048576

CREATE TABLE #drives (drive char(1) PRIMARY KEY,
                      FreeSpace int NULL,
                      TotalSize int NULL)

INSERT #drives(drive,FreeSpace)
EXEC master.dbo.xp_fixeddrives

EXEC @hr=sp_OACreate 'Scripting.FileSystemObject',@fso OUT
IF @hr <> 0 EXEC sp_OAGetErrorInfo @fso

DECLARE dcur CURSOR LOCAL FAST_FORWARD
FOR SELECT drive from #drives
ORDER by drive

OPEN dcur

FETCH NEXT FROM dcur INTO @drive

WHILE @@FETCH_STATUS=0
BEGIN

        EXEC @hr = sp_OAMethod @fso,'GetDrive', @odrive OUT, @drive
        IF @hr <> 0 EXEC sp_OAGetErrorInfo @fso
        
        EXEC @hr = sp_OAGetProperty @odrive,'TotalSize', @TotalSize OUT
        IF @hr <> 0 EXEC sp_OAGetErrorInfo @odrive
                        
        UPDATE #drives
        SET TotalSize=@TotalSize/@MB
        WHERE drive=@drive
        
        FETCH NEXT FROM dcur INTO @drive

END

CLOSE dcur
DEALLOCATE dcur

EXEC @hr=sp_OADestroy @fso
IF @hr <> 0 EXEC sp_OAGetErrorInfo @fso

SELECT drive,
       FreeSpace as 'Livre(MB)',
       TotalSize as 'Total(MB)',
       CAST((FreeSpace/(TotalSize*1.0))*100.0 as int) as 'Livre(%)'
FROM #drives
ORDER BY drive

DROP TABLE #drives

RETURN
go

É isso guri, grande abraço!

Thiago Zavaschi
Thiago Zavaschi
11/5/2010 22:14:35 #

Agora que vi que "viajei na maionese"!
Esse script que postei é pra verificar o espaço em disco.
A solução que uso é essa (bem mais simples):

-- Ordenado por quantidade de linhas
SELECT object_name(id), rowcnt, dpages * 8 AS [tamanho KB] FROM sysindexes
WHERE indid IN (1,0) AND objectproperty(id,'isusertable') = 1
ORDER BY rowcnt DESC
-- Ordenado por tamanho físico
SELECT object_name(id), rowcnt, dpages * 8 AS [tamanho KB] FROM sysindexes
WHERE indid IN (1,0) AND objectproperty(id,'isusertable') = 1
ORDER BY [tamanho KB] DESC

Marcelo
Marcelo
12/5/2010 09:05:48 #

Diego,
Também gostaria de contribuir com um script um pouco mais simples, embora que no seu script poderíamos evitar o cursor com a proc não documentada "sp_msforeachtable", a solução que tenho além de usar esta proc usa uma outra proc também não documentada a "sp_mstablespace".

script para uma única linha de código.

sp_msforeachtable "exec sp_mstablespace '?'"

Att.
Marcelo Fernandes
@marcelodba

pingback
zavaschi.com
12/5/2010 12:44:58 #

Pingback from zavaschi.com

Verificando espaço em disco e o espaço ocupado por tabelas! « Thiago Zavaschi R2

laerte Junior
laerte Junior
12/5/2010 21:50:22 #

Grande Diego,

Como eu gosto de dizer, o Ótimo é inimigo do Bom. Tu precisava de algo rapido e eu não entrei em detalhes em saber porque. Pode não ser a melhor solução, mas acredito que tenha lhe ajudado.
QQ coisa estamos ai meu amigo (mesmo vc sendo corintiano hahahah)

Thiago Zavaschi
Thiago Zavaschi
13/5/2010 12:08:14 #

Marcelo,
O único problema é o "não documentado". MAs como disse antes, as coisas mais legais no SQL Server não são documentadas hehehe Smile

Thiago Zavaschi
Thiago Zavaschi
13/5/2010 12:18:24 #

Marcelo, outra coisa...
O script não gera os nomes das tabelas.
Pra ajudar poderia fazer algo como:
sp_msforeachtable "select '?'; exec sp_mstablespace '?'"
E botar a saída em texto (ou arquivo)!

Abraços pessoal!

trackback
Think Think .Net
14/5/2010 20:36:47 #

Como encontrar objetos do Database no SQL Server?

Como encontrar objetos do Database no SQL Server?

jodhpur guest house
jodhpur guest house
8/11/2010 05:56:43 #

I like this blog and also their post. Thanks for sharing this pretty article. It's a great article for me. Thanks!

pingback
pessoalex.wordpress.com
18/4/2011 13:21:21 #

Pingback from pessoalex.wordpress.com

Como calcular a massa de dados no SQL Server? « Alex Souza

gucci outlet online
gucci outlet online
12/5/2011 23:52:03 #

These are wonderful! Thank you for sharing

pingback
diegonogare.net
3/9/2011 21:01:25 #

Pingback from diegonogare.net

Como encontrar objetos do Database no SQL Server?

Comentar


(Vai mostrar seu Gravatar)

  Country flag

biuquote
  • Comentário
  • Pré-visualização
Loading




SQL Server

SQL Server



Codificando .Net

SQL PASS