Kích thước bảng và chỉ mục trong SQL Server


90

Chúng ta có thể có một truy vấn SQL về cơ bản sẽ giúp xem kích thước bảng và chỉ mục trong SQl Server không.

Làm cách nào máy chủ SQL duy trì việc sử dụng bộ nhớ cho các bảng / chỉ mục?


1
Bạn cũng có thể thấy thủ tục được lưu trữ sp_helpdbhữu ích
Zack Burt

1
Có đã trả lời cho điều này, nhưng cá nhân tôi sử dụng truy vấn trong liên kết này: qualityofdata.com/2011/02/02/...
naiem

Câu trả lời:


73

Các exec sp_spaceusedkhông tham số hiển thị tóm tắt cho toàn bộ cơ sở dữ liệu. Giải pháp foreachtable tạo một tập hợp kết quả cho mỗi bảng - SSMS có thể không xử lý được nếu bạn có quá nhiều bảng.

Tôi đã tạo một tập lệnh thu thập thông tin bảng thông qua sp_spaceusedvà hiển thị một bản tóm tắt trong một tập hợp bản ghi duy nhất, được sắp xếp theo kích thước.

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
Tập lệnh của bạn chỉ xử lý các bảng trong lược đồ 'dbo'. Nếu tôi có một bảng trong cơ sở dữ liệu của mình với lược đồ 'Audit', thì sp_spaceused cần phải được gọi như sau: execute sp_spaceused 'Audit.Data'. Vì vậy, tập lệnh cần được sửa đổi để cung cấp cho nó tên bảng được mở đầu bằng tên lược đồ (phân tách bằng dấu chấm) để nó trả về dữ liệu về các bảng từ các lược đồ khác.
Baodad

1
Điểm tốt @Boadad ... đó sẽ là một bản sửa lỗi siêu dễ dàng. Thay thế "select name from sysobjects where xtype = 'U'" bằng this sẽ thực hiện thủ thuật: "select '[' + sc.name + ']. [' + S.name + ']' FROM sysobjects's INNER JOIN sys .schemas sc ON s.uid = sc.schema_id where s.xtype = 'U' "Tập lệnh tuyệt vời, cảm ơn!
DCaugs

Thay vì sử dụng bảng tạm thời, chúng ta có thể chèn dữ liệu vào bảng khác không phải là bảng tạm thời không?
Prabhakar

@PrabhakarPandey Chắc chắn chỉ cần xóa #.
Racer SQL

120

sp_spaceused cung cấp cho bạn kích thước của tất cả các chỉ mục được kết hợp.

Nếu bạn muốn kích thước của mỗi chỉ mục cho một bảng, hãy sử dụng một trong hai truy vấn sau:

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

Kết quả thường hơi khác một chút nhưng trong vòng 1%.


Truy vấn đầu tiên bao gồm các khóa chính, điều này hơi khó hiểu vì một vài lý do.
quillbreaker

Truy vấn thứ hai ném Msg 102, Level 15, State 1, Line 5 - Incorrect syntax near '('.vào tôi, nhưng tôi không thể thấy bất kỳ vấn đề nào với cú pháp. Bất kỳ ý tưởng?
Oliver

Oliver, bạn đang chạy phiên bản nào? Nó hoạt động như hiện tại đối với tôi trong 2008R2 và 2012.
Rob Garrison

24

Trên SQL 2012, việc lấy thông tin này ở cấp bảng đã trở nên rất đơn giản:

SQL Management Studio -> Nhấp chuột phải vào Db -> Báo cáo -> Báo cáo Chuẩn -> Sử dụng đĩa theo bảng!

Thưởng thức


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

3
Nếu bạn đăng các mẫu mã, XML hoặc dữ liệu, VUI LÒNG đánh dấu các dòng đó trong trình soạn thảo văn bản và nhấp vào nút "mẫu mã" ( { }) trên thanh công cụ của trình soạn thảo để định dạng độc đáo và đánh dấu cú pháp!
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

Đây là phiên bản nhỏ gọn hơn của câu trả lời thành công nhất:

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

Đã lâu kể từ khi tạo bài đăng này nhưng tôi muốn chia sẻ kịch bản của mình:

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

nó hoạt động cho:

  • SQL Server (bắt đầu từ 2008)
  • Bao gồm thông tin cho tất cả các bảng trên mỗi cơ sở dữ liệu hiện tại

0

Có một thủ tục được lưu trữ mở rộng sp_spaceusedđể đưa thông tin này ra ngoài. Nó khá phức tạp để làm điều đó từ từ điển dữ liệu, nhưng Điều này liên kết người hâm mộ với một tập lệnh thực hiện điều đó. Câu hỏi stackoverflow này có một số thông tin về cấu trúc dữ liệu cơ bản mà bạn có thể sử dụng để xây dựng ước tính về kích thước bảng và chỉ mục cho việc lập kế hoạch thành công.


0

Truy vấn này đến từ hai câu trả lời khác:

Nhận kích thước của tất cả các bảng trong cơ sở dữ liệu

Làm cách nào để tìm các đối tượng lớn nhất trong cơ sở dữ liệu SQL Server?

, nhưng tôi đã nâng cao điều này để trở nên phổ biến. Nó sử dụng sys.objectstừ điển:

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
;
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.