Как узнать, какие таблицы занимают больше всего места в базе данных SQL Server 2005?

91

Как узнать, какие таблицы занимают больше всего места в базе данных SQL Server 2005?

Я уверен, что существует какая-то системная хранимая процедура, которая показывает эту информацию.

У меня есть тестовая база данных, которая выросла с 1 ТБ до 23 ТБ. В настоящее время мы проводим большое количество клиентских тестов преобразования в базе данных, что влечет за собой выполнение одной и той же хранимой процедуры преобразования несколько раз. Он выполняет DELETE, что, я уверен, увеличивает журнал транзакций. Но это заставило меня задуматься над этим вопросом.

Информация

Большая проблема - это таблица dbo.Download, она создает огромное хранилище, которое на самом деле не нужно, у меня было 3 ГБ до его усечения, затем 52 МБ;)

Герхард Вайс
источник
2
Ответы Marc_S и Barry были просто выдающимися, поэтому я поддержал их обоих и ждал, чтобы увидеть, какой из них получил наибольшее количество голосов, чтобы я мог наградить его «принятым ответом». Но они оба были равны по 5, поэтому я просто выбрал один, но использовал оба. Большое спасибо Marc_S и Barry!
Герхард Вайс,

Ответы:

209

Попробуйте этот сценарий - он перечислит количество строк и пространство, используемое строками данных (и общее используемое пространство) для всех таблиц в вашей базе данных:

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) 
marc_s
источник
6
+1 Великолепно. Обратите внимание, что это не включает размер индексов данных. Однако для меня это сделало свою работу.
Эрик Робертсон
40
Я этого не знал, но если вы используете Management Studio, вы также можете щелкнуть правой кнопкой мыши базу данных и перейти в Отчеты -> Использование диска по таблице для тех же результатов.
rossisdead
@rossisdead, это забавная информация, которую нужно знать. Благодарность!
Никмаович
Я получаю sys.tables «Таблица„“не существует»
Seano
@Seano: какую версию SQL Server вы используете? (бегите, SELECT @@VERSIONчтобы узнать) Какой уровень совместимости с базой данных у вашей базы данных ??
marc_s
33

Используйте sp_spacedUsed

Exec sp_spaceused N'YourTableName'

Или, если вы хотите выполнить sp_spaceusedдля каждой таблицы в своей базе данных, вы можете использовать этот SQL:

set nocount on
create table #spaceused (
  name nvarchar(120),
  rows char(11),
  reserved varchar(18),
  data varchar(18),
  index_size varchar(18),
  unused varchar(18)
)

declare Tables cursor for
  select name
  from sysobjects where type='U'
  order by name asc

OPEN Tables
DECLARE @table varchar(128)

FETCH NEXT FROM Tables INTO @table

WHILE @@FETCH_STATUS = 0
BEGIN
  insert into #spaceused exec sp_spaceused @table
  FETCH NEXT FROM Tables INTO @table
END

CLOSE Tables
DEALLOCATE Tables 

select * from #spaceused
drop table #spaceused

exec sp_spaceused

Вышеупомянутый SQL отсюда

кодирование
источник
7
Для более новых версий SQL Server вы также можете использоватьexec sp_msforeachtable 'exec sp_spaceused N''?'''
JNK,
1
@JNK sp_msforeachtableсуществует как минимум с SQl Server 2000
SQLMenace
@SQLMenace - спасибо за информацию. Я не исследовал, сколько ему лет перед публикацией, но не был уверен, что найду его, поскольку он недокументирован.
JNK,
4
Немного более простой пример: Вы можете уйти с пропуская EXECS и фантазии квотирования, делая только , sp_msforeachtable 'sp_spaceused [?]'если вам нравится. Проверено обратно на SQL2000.
Марк
Отметьте, что проблема этого метода в том, что он не возвращается как единый набор результатов
Пол
8

Комментарий Rossisdead ответил на этот вопрос лучше всего для меня, я бы хотел, чтобы он не был похоронен в комментарии. Это будет полезно для таких людей, как я, не пытающихся написать сценарий решения (OP не запрашивал фрагмент кода)

Если вы используете Management Studio, вы также можете щелкнуть правой кнопкой мыши по базе данных и перейти в Отчеты -> Использование диска по таблице для тех же результатов.

Hucker
источник
Для акцента: щелкните правой кнопкой мыши базу данных, а не экземпляр сервера
dhollenbeck
4

Спасибо @marc_s за ответ. Мне нужно было знать данные и пространство индекса, поэтому я продолжил и расширил запрос, включив это.

SELECT TableName
    , SUM(DataRowCounts) AS DataRowCounts
    , SUM(DataTotalSpaceGB) AS DataTotalSpaceGB
    , SUM(DataSpaceUsedGB) AS DataSpaceUsedGB
    , SUM(DataUnusedSpaceGB) AS DataUnusedSpaceGB
    , SUM(IndexRowCounts) AS IndexRowCounts
    , SUM(IndexTotalSpaceGB) AS IndexTotalSpaceGB
    , SUM(IndexSpaceUsedGB) AS IndexSpaceUsedGB
    , SUM(IndexUnusedSpaceGB) AS IndexUnusedSpaceGB
    , SUM(DataTotalSpaceGB) + SUM(IndexTotalSpaceGB) AS TotalSpaceGB
FROM
(
SELECT t.NAME AS TableName
    , i.type_desc AS IndexType
    , CASE WHEN i.type_desc IN ('CLUSTERED', 'CLUSTERED COLUMNSTORE', 'HEAP') THEN CAST(ROUND(((SUM(a.total_pages) * 8) / 1024.00), 2)/1000 AS NUMERIC(36, 2)) ELSE 0 END AS DataTotalSpaceGB
    , CASE WHEN i.type_desc IN ('CLUSTERED', 'CLUSTERED COLUMNSTORE', 'HEAP') THEN CAST(ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2)/1000 AS NUMERIC(36, 2))  ELSE 0 END AS DataSpaceUsedGB    
    , CASE WHEN i.type_desc IN ('CLUSTERED', 'CLUSTERED COLUMNSTORE', 'HEAP') THEN CAST(ROUND(((SUM(a.total_pages) - SUM(a.used_pages)) * 8) / 1024.00, 2)/1000 AS NUMERIC(36, 2)) ELSE 0 END AS DataUnusedSpaceGB
    , CASE WHEN i.type_desc IN ('CLUSTERED', 'CLUSTERED COLUMNSTORE', 'HEAP') THEN SUM(p.Rows) ELSE 0 END AS DataRowCounts
    , CASE WHEN i.type_desc = 'NONCLUSTERED' THEN CAST(ROUND(((SUM(a.total_pages) * 8) / 1024.00), 2)/1000 AS NUMERIC(36, 2)) ELSE 0 END AS IndexTotalSpaceGB
    , CASE WHEN i.type_desc = 'NONCLUSTERED' THEN CAST(ROUND(((SUM(a.used_pages) * 8) / 1024.00), 2)/1000 AS NUMERIC(36, 2))  ELSE 0 END AS IndexSpaceUsedGB    
    , CASE WHEN i.type_desc = 'NONCLUSTERED' THEN CAST(ROUND(((SUM(a.total_pages) - SUM(a.used_pages)) * 8) / 1024.00, 2)/1000 AS NUMERIC(36, 2)) ELSE 0 END AS IndexUnusedSpaceGB  
    , CASE WHEN i.type_desc = 'NONCLUSTERED' THEN SUM(p.Rows) ELSE 0 END AS IndexRowCounts
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
LEFT JOIN sys.schemas s ON t.schema_id = s.schema_id
WHERE t.NAME NOT LIKE 'dt%'
    AND t.is_ms_shipped = 0
    AND i.OBJECT_ID > 255
    AND s.Name = 'dbo' --update this filter
    AND t.Name = 'MyTable'
GROUP BY t.Name
    , i.type_desc
) x
GROUP BY TableName
ORDER BY TotalSpaceGB DESC
Kjmerf
источник