Розмір таблиці та індексу в SQL Server


90

Чи можемо ми мати запит SQL, який в основному допоможе переглядати розміри таблиць та індексів на сервері SQl.

Як SQL-сервер підтримує використання пам'яті для таблиць / індексів?


1
Збережена процедура також може виявитися вам sp_helpdbкорисною
Zack Burt

1
Там вже відповідає на це, але я особисто використовую запит в цьому посиланню: qualityofdata.com/2011/02/02 / ...
naiem

Відповіді:


73

Параметр exec sp_spaceusedwithout відображає зведення для всієї бази даних. Рішення, що передбачає прогнозування, генерує один набір результатів для таблиці - який, можливо, SSMS не зможе обробити, якщо у вас занадто багато таблиць.

Я створив сценарій, який збирає таблицю з інформацією sp_spaceusedта відображає зведення в одному наборі записів, відсортованих за розміром.

create table #t
(
  name nvarchar(128),
  rows varchar(50),
  reserved varchar(50),
  data varchar(50),
  index_size varchar(50),
  unused varchar(50)
)

declare @id nvarchar(128)
declare c cursor for
select '[' + sc.name + '].[' + s.name + ']' FROM sysobjects s INNER JOIN sys.schemas sc ON s.uid = sc.schema_id where s.xtype='U'

open c
fetch c into @id

while @@fetch_status = 0 begin

  insert into #t
  exec sp_spaceused @id

  fetch c into @id
end

close c
deallocate c

select * from #t
order by convert(int, substring(data, 1, len(data)-3)) desc

drop table #t

4
Ваш скрипт обробляє лише таблиці у схемі 'dbo'. Якщо в моїй базі даних є таблиця зі схемою "Аудит", sp_spaceused потрібно викликати так: exec sp_spaceused "Audit.Data". Отже, сценарій потрібно змінити, щоб подати до нього назву таблиці, перед якою вказано ім’я схеми (відокремлене крапкою), щоб він повертав дані про таблиці з інших схем.
Баодад

1
Хороший момент @Boadad ... це повинно бути надзвичайно простим виправленням. Заміна "вибрати ім'я з sysobjects, де xtype = 'U'", на це має зробити трюк: "select '[' + sc.name + ']. [' + S.name + ']' FROM sysobjects s ​​INNER JOIN sys .schemas sc ON s.uid = sc.schema_id де s.xtype = 'U' "Чудовий сценарій, дякую!
DCaugs

замість використання тимчасової таблиці ми можемо вставити дані в іншу таблицю, яка не є тимчасовою?
Прабхакар,

@PrabhakarPandey Звичайно, просто видаліть #.
Racer SQL

120

sp_spaceused дає вам розмір усіх індексів разом узятих.

Якщо вам потрібен розмір кожного індексу для таблиці, використовуйте один із цих двох запитів:

SELECT
    i.name                  AS IndexName,
    SUM(s.used_page_count) * 8   AS IndexSizeKB
FROM sys.dm_db_partition_stats  AS s 
JOIN sys.indexes                AS i
ON s.[object_id] = i.[object_id] AND s.index_id = i.index_id
WHERE s.[object_id] = object_id('dbo.TableName')
GROUP BY i.name
ORDER BY i.name

SELECT
    i.name              AS IndexName,
    SUM(page_count * 8) AS IndexSizeKB
FROM sys.dm_db_index_physical_stats(
    db_id(), object_id('dbo.TableName'), NULL, NULL, 'DETAILED') AS s
JOIN sys.indexes AS i
ON s.[object_id] = i.[object_id] AND s.index_id = i.index_id
GROUP BY i.name
ORDER BY i.name

Результати зазвичай дещо відрізняються, але в межах 1%.


Перший запит включає первинні ключі, що трохи заплутано з кількох причин.
quillbreaker

Другий запит кидає Msg 102, Level 15, State 1, Line 5 - Incorrect syntax near '('.на мене, але я не бачу жодних проблем із синтаксисом. Будь-яка ідея?
Олівер

Олівере, на якій версії ти працюєш? Для мене це працює як є у 2008 R2 та 2012 рр.
Роб Гаррісон,

24

У SQL 2012 отримати цю інформацію на рівні таблиці стало дуже просто:

Студія управління SQL -> Клацніть правою кнопкою миші на Db -> Звіти -> Стандартні звіти -> Використання диска за таблицею!

Насолоджуйтесь


13
EXEC sp_MSforeachtable @command1="EXEC sp_spaceused '?'"

3
Якщо ви розміщуєте поштовий індекс, зразки XML або даних, ПРОСИМО, виділіть ці рядки в текстовому редакторі та натисніть кнопку "Зразки коду" ( { }) на панелі інструментів редактора, щоб гарно відформатувати та виділити синтаксис!
marc_s

4
--Gets the size of each index for the specified table
DECLARE @TableName sysname = N'SomeTable';

SELECT i.name AS IndexName
      ,8 * SUM(s.used_page_count) AS IndexSizeKB
FROM sys.indexes AS i
    INNER JOIN sys.dm_db_partition_stats AS s 
        ON i.[object_id] = s.[object_id] AND i.index_id = s.index_id
WHERE s.[object_id] = OBJECT_ID(@TableName, N'U')
GROUP BY i.name
ORDER BY i.name;

SELECT i.name AS IndexName
      ,8 * SUM(a.used_pages) AS IndexSizeKB
FROM sys.indexes AS i
    INNER JOIN sys.partitions AS p 
        ON i.[object_id]  = p.[object_id] AND i.index_id = p.index_id
    INNER JOIN sys.allocation_units AS a 
        ON p.partition_id = a.container_id
WHERE i.[object_id] = OBJECT_ID(@TableName, N'U')
GROUP BY i.name
ORDER BY i.name;

3

Ось більш компактна версія найуспішнішої відповіді:

create table #tbl(
  name nvarchar(128),
  rows varchar(50),
  reserved varchar(50),
  data varchar(50),
  index_size varchar(50),
  unused varchar(50)
)

exec sp_msforeachtable 'insert into #tbl exec sp_spaceused [?]'

select * from #tbl
    order by convert(int, substring(data, 1, len(data)-3)) desc

drop table #tbl

3

з часу створення цієї публікації минуло багато часу, але я хотів поділитися своїм сценарієм:

WITH CteIndex
AS
(
SELECT 
     reservedpages = (reserved_page_count)
     ,usedpages = (used_page_count)
     ,pages = (
            CASE
                WHEN (s.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
            )    
     ,s.object_id   
     ,i.index_id        
     ,i.type_desc AS IndexType
     ,i.name AS indexname
    FROM sys.dm_db_partition_stats s
    INNER JOIN sys.indexes i ON s.[object_id] = i.[object_id] AND s.index_id = i.index_id   
)
SELECT DISTINCT
DB_NAME(DB_ID()) AS DatabaseName
,o.name AS TableName
,o.object_id
,ct.indexname
,ct.IndexType
,ct.index_id
, IndexSpace = LTRIM (STR ((CASE WHEN usedpages > pages THEN CASE WHEN ct.index_id < 2 THEN  pages ELSE (usedpages - pages) END ELSE 0 END) * 8, 15, 0) + ' KB')
FROM CteIndex ct
INNER JOIN sys.objects o ON o.object_id = ct.object_id
INNER JOIN sys.dm_db_index_physical_stats (DB_ID(), NULL, NULL, NULL , NULL) ps ON ps.object_id = o.object_id
AND ps.index_id = ct.index_id
ORDER BY name ASC

це працює для:

  • SQL Server (починаючи з 2008 року)
  • Включає інформацію для всіх таблиць для поточної бази даних

0

Існує розширена збережена процедура, sp_spaceusedяка виводить цю інформацію. Це досить заплутано робити це зі словника даних, але це посилання спрямовується на сценарій, який це робить. Це запитання щодо stackoverflow містить деякі роздуми щодо інформації про основні структури даних, які ви можете використовувати для побудови оцінок розмірів таблиць та індексів для планування капіталізації.


0

Цей запит походить від двох інших відповідей:

Отримати розмір усіх таблиць у базі даних

Як знайти найбільші об’єкти в базі даних SQL Server?

, але я покращив це, щоб бути універсальним. Він використовує sys.objectsсловник:

SELECT 
    s.NAME as SCHEMA_NAME,
    t.NAME AS OBJ_NAME,
    t.type_desc as OBJ_TYPE,
    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.objects t
INNER JOIN
    sys.schemas s ON t.SCHEMA_ID = s.SCHEMA_ID 
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 
    s.NAME, t.NAME, t.type_desc, i.object_id, i.index_id, i.name 
ORDER BY
    sum(a.total_pages) DESC
;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.