Think Think .Net
Diego Nogare [MVP | MCT | MCITP | MCTS | MCP | INETA BR]

Como calcular a massa de dados no SQL Server?

terça-feira, 11 maio 2010 06:36 by Nogare

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

maio 11. 2010 20:13

pingback

Pingback from topsy.com

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

topsy.com

maio 12. 2010 02:53

Fernando H. Rosa

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

Fernando H. Rosa

maio 12. 2010 06:37

Thiago Zavaschi

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

maio 12. 2010 07:14

Thiago Zavaschi

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

Thiago Zavaschi

maio 12. 2010 18:05

Marcelo

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

Marcelo

maio 12. 2010 21:44

pingback

Pingback from zavaschi.com

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

zavaschi.com

maio 13. 2010 06:50

laerte Junior

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)

laerte Junior

maio 13. 2010 21:08

Thiago Zavaschi

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

maio 13. 2010 21:18

Thiago Zavaschi

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!

Thiago Zavaschi

maio 15. 2010 05:36

trackback

Como encontrar objetos do Database no SQL Server?

Como encontrar objetos do Database no SQL Server?

Think Think .Net

agosto 5. 2010 03:30

Seattle Limos

I would just say one thing to you and that is, “FANTASTIC”!! Keep it up and wish to get more details from your blog.

Seattle Limos

agosto 6. 2010 01:15

Nude Chat

Do you mind if I quote you on my blog if I link back to your website?

Nude Chat

agosto 6. 2010 23:04

Nude Cam

Just wanted to give you a shout from the valley of the sun, great information. Much appreciated.

Nude Cam

agosto 9. 2010 01:14

Chat Cam

Thanks for the post. Im  a big fan of the blog, i've even put a little bookmark right on the tool bar of my Firefox you'll be happy to find out!

Chat Cam

agosto 18. 2010 11:09

sex chat

Hello,I love reading through your blog, I wanted to leave a little comment to support you and wish you a good continuation. Wishing you the best of luck for all your blogging efforts.

sex chat

agosto 27. 2010 23:47

Music Ringtones

I always learn something new.

Music Ringtones

agosto 28. 2010 00:50

Cell Phone Ringtones

I always learn something new.

Cell Phone Ringtones

agosto 28. 2010 00:57

Premium Wordpress Themes

Very useful post. Stay tuned!!!

Premium Wordpress Themes

Comentar


(Vai mostrar seu Gravatar)

  Country flag

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