Como encontrar os maiores objetos em um banco de dados do SQL Server?

136

Como eu iria encontrar os maiores objetos em um banco de dados do SQL Server? Primeiro, determinando quais tabelas (e índices relacionados) são as maiores e, em seguida, determinando quais linhas em uma tabela específica são maiores (estamos armazenando dados binários em BLOBs)?

Existem ferramentas para ajudar nesse tipo de análise de banco de dados? Ou existem algumas consultas simples que eu poderia executar nas tabelas do sistema?

jamesaharvey
fonte

Respostas:

280

Eu uso esse script SQL (que recebi de alguém em algum lugar - não consigo reconstruir de quem ele veio) há séculos e isso me ajudou a entender e determinar o tamanho de índices e tabelas:

SELECT 
    t.name AS TableName,
    i.name as indexName,
    sum(p.rows) as RowCounts,
    sum(a.total_pages) as TotalPages, 
    sum(a.used_pages) as UsedPages, 
    sum(a.data_pages) as DataPages,
    (sum(a.total_pages) * 8) / 1024 as TotalSpaceMB, 
    (sum(a.used_pages) * 8) / 1024 as UsedSpaceMB, 
    (sum(a.data_pages) * 8) / 1024 as DataSpaceMB
FROM 
    sys.tables t
INNER JOIN      
    sys.indexes i ON t.object_id = i.object_id
INNER JOIN 
    sys.partitions p ON i.object_id = p.object_id AND i.index_id = p.index_id
INNER JOIN 
    sys.allocation_units a ON p.partition_id = a.container_id
WHERE 
    t.name NOT LIKE 'dt%' AND
    i.object_id > 255 AND  
    i.index_id <= 1
GROUP BY 
    t.name, i.object_id, i.index_id, i.name 
ORDER BY 
    object_name(i.object_id) 

Obviamente, você pode usar outro critério de pedido, por exemplo,

ORDER BY SUM(p.rows) DESC

para obter as tabelas com mais linhas ou

ORDER BY SUM(a.total_pages) DESC

para obter as tabelas com mais páginas (8K blocos) usadas.

marc_s
fonte
Excelente, obrigado! Agora, que reduzi meu maior objeto a uma tabela que contém muitos dados binários, para descobrir qual das linhas de dados binários é a maior?
precisa saber é o seguinte
3
para isso, você deve selecionar essa tabela e imprimir DATALENGTH (campo) para cada campo em que estiver interessado (normalmente VARCHAR (MAX), VARBINARY (MAX) e assim por diante)
marc_s
1
Obrigado @marc_s, isso foi muito útil. A coluna TableName também pode incluir o nome do esquema comSELECT OBJECT_SCHEMA_NAME(i.object_id) + '.' + OBJECT_NAME(i.object_id) AS TableName, ...
CruiZen
2
Esse deve ser o roteiro mais bonito TSQL que eu já vi
Agustin Meriles
2
Para incluir também índices NÃO CLUSTERED, remova "e i.index_id <= 1" da cláusula WHERE.
Gordon Bell
72

No SQL Server 2008, você também pode executar o relatório padrão Uso de Disco pelas Principais Tabelas. Isso pode ser encontrado clicando com o botão direito do mouse no banco de dados, selecionando Relatórios-> Relatórios padrão e selecionando o relatório que você deseja.

Gregory Lancaster
fonte
8
Sem brincadeiras? Essa é uma resposta tão revolucionária. Obrigado por publicá-lo. (. Não sarcasmo têm funcionado essas consultas manualmente por um tempo agora e eu não posso acreditar que estes relatórios já estão lá!)
Jennifer Zouak
4

Esta consulta ajuda a encontrar a maior tabela em sua conexão.

SELECT  TOP 1 OBJECT_NAME(OBJECT_ID) TableName, st.row_count
FROM sys.dm_db_partition_stats st
WHERE index_id < 2
ORDER BY st.row_count DESC
Vinoth_S
fonte
É bom ter algo que possamos memorizar facilmente. Obrigado pela concisão.
David Betz
3

Você também pode usar o seguinte código:

USE AdventureWork
GO
CREATE TABLE #GetLargest 
(
  table_name    sysname ,
  row_count     INT,
  reserved_size VARCHAR(50),
  data_size     VARCHAR(50),
  index_size    VARCHAR(50),
  unused_size   VARCHAR(50)
)

SET NOCOUNT ON

INSERT #GetLargest

EXEC sp_msforeachtable 'sp_spaceused ''?'''

SELECT 
  a.table_name,
  a.row_count,
  COUNT(*) AS col_count,
  a.data_size
  FROM #GetLargest a
     INNER JOIN information_schema.columns b
     ON a.table_name collate database_default
     = b.table_name collate database_default
       GROUP BY a.table_name, a.row_count, a.data_size
       ORDER BY CAST(REPLACE(a.data_size, ' KB', '') AS integer) DESC

DROP TABLE #GetLargest
Dheeraj Bansal
fonte
2

Se você estiver usando o Sql Server Management Studio 2008, existem determinados campos de dados que podem ser exibidos na janela de detalhes do explorador de objetos. Basta procurar e selecionar a pasta de tabelas. Na exibição de detalhes, você pode clicar com o botão direito do mouse nos títulos das colunas e adicionar campos ao "relatório". Sua milhagem pode variar se você estiver no SSMS 2008 express.

doug_w
fonte
2

Encontrei esta consulta também muito útil no SqlServerCentral, aqui está o link para a postagem original

Tabelas maiores do Sql Server

  select name=object_schema_name(object_id) + '.' + object_name(object_id)
, rows=sum(case when index_id < 2 then row_count else 0 end)
, reserved_kb=8*sum(reserved_page_count)
, data_kb=8*sum( case 
     when index_id<2 then in_row_data_page_count + lob_used_page_count + row_overflow_used_page_count 
     else lob_used_page_count + row_overflow_used_page_count 
    end )
, index_kb=8*(sum(used_page_count) 
    - sum( case 
           when index_id<2 then in_row_data_page_count + lob_used_page_count + row_overflow_used_page_count 
        else lob_used_page_count + row_overflow_used_page_count 
        end )
     )    
, unused_kb=8*sum(reserved_page_count-used_page_count)
from sys.dm_db_partition_stats
where object_id > 1024
group by object_id
order by 
rows desc   

No meu banco de dados, eles deram resultados diferentes entre esta consulta e a 1ª resposta.

Espero que alguém ache útil

Franco
fonte
1

A resposta de @ marc_s é muito boa e eu a uso há alguns anos. No entanto, notei que o script perde dados em alguns índices columnstore e não mostra uma imagem completa. Por exemplo, quando você faz uma SUM(TotalSpace)comparação com o script e o compara com a propriedade de banco de dados de espaço total no Management Studio, os números não correspondem no meu caso (o Management Studio mostra números maiores). Modifiquei o script para superar esse problema e o estendi um pouco:

select
    tables.[name] as table_name,
    schemas.[name] as schema_name,
    isnull(db_name(dm_db_index_usage_stats.database_id), 'Unknown') as database_name,
    sum(allocation_units.total_pages) * 8 as total_space_kb,
    cast(round(((sum(allocation_units.total_pages) * 8) / 1024.00), 2) as numeric(36, 2)) as total_space_mb,
    sum(allocation_units.used_pages) * 8 as used_space_kb,
    cast(round(((sum(allocation_units.used_pages) * 8) / 1024.00), 2) as numeric(36, 2)) as used_space_mb,
    (sum(allocation_units.total_pages) - sum(allocation_units.used_pages)) * 8 as unused_space_kb,
    cast(round(((sum(allocation_units.total_pages) - sum(allocation_units.used_pages)) * 8) / 1024.00, 2) as numeric(36, 2)) as unused_space_mb,
    count(distinct indexes.index_id) as indexes_count,
    max(dm_db_partition_stats.row_count) as row_count,
    iif(max(isnull(user_seeks, 0)) = 0 and max(isnull(user_scans, 0)) = 0 and max(isnull(user_lookups, 0)) = 0, 1, 0) as no_reads,
    iif(max(isnull(user_updates, 0)) = 0, 1, 0) as no_writes,
    max(isnull(user_seeks, 0)) as user_seeks,
    max(isnull(user_scans, 0)) as user_scans,
    max(isnull(user_lookups, 0)) as user_lookups,
    max(isnull(user_updates, 0)) as user_updates,
    max(last_user_seek) as last_user_seek,
    max(last_user_scan) as last_user_scan,
    max(last_user_lookup) as last_user_lookup,
    max(last_user_update) as last_user_update,
    max(tables.create_date) as create_date,
    max(tables.modify_date) as modify_date
from 
    sys.tables
    left join sys.schemas on schemas.schema_id = tables.schema_id
    left join sys.indexes on tables.object_id = indexes.object_id
    left join sys.partitions on indexes.object_id = partitions.object_id and indexes.index_id = partitions.index_id
    left join sys.allocation_units on partitions.partition_id = allocation_units.container_id
    left join sys.dm_db_index_usage_stats on tables.object_id = dm_db_index_usage_stats.object_id and indexes.index_id = dm_db_index_usage_stats.index_id
    left join sys.dm_db_partition_stats on tables.object_id = dm_db_partition_stats.object_id and indexes.index_id = dm_db_partition_stats.index_id
group by schemas.[name], tables.[name], isnull(db_name(dm_db_index_usage_stats.database_id), 'Unknown')
order by 5 desc

Espero que seja útil para alguém. Este script foi testado em grandes bancos de dados de toda a TB com centenas de tabelas, índices e esquemas diferentes.

dyatchenko
fonte