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?


136

Làm thế nào tôi có thể tìm kiếm các đối tượng lớn nhất trong cơ sở dữ liệu SQL Server? Đầu tiên, bằng cách xác định bảng nào (và các chỉ số liên quan) là lớn nhất và sau đó xác định hàng nào trong một bảng cụ thể là lớn nhất (chúng tôi đang lưu trữ dữ liệu nhị phân trong BLOB)?

Có công cụ nào để giúp phân tích cơ sở dữ liệu này không? Hoặc có một số truy vấn đơn giản tôi có thể chạy với các bảng hệ thống?

Câu trả lời:


280

Tôi đã sử dụng tập lệnh SQL này (mà tôi đã nhận được từ một người nào đó, ở đâu đó - không thể tái tạo lại nó đến từ ai) và nó đã giúp tôi hiểu được khá nhiều và xác định kích thước của các chỉ mục và bảng:

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) 

Tất nhiên, bạn có thể sử dụng một tiêu chí đặt hàng khác, vd

ORDER BY SUM(p.rows) DESC

để có được các bảng có nhiều hàng nhất hoặc

ORDER BY SUM(a.total_pages) DESC

để có được các bảng có nhiều trang nhất (khối 8K) được sử dụng.


Tuyệt vời cảm ơn bạn! Bây giờ, tôi đã thu hẹp đối tượng lớn nhất của mình vào một bảng chứa nhiều dữ liệu nhị phân, dù sao để tìm ra hàng nào trong số các hàng dữ liệu nhị phân là lớn nhất?
jamesaharvey

3
để làm được điều đó, bạn phải thực hiện một lựa chọn trên bảng đó và in ra DATALENGTH (trường) cho từng trường mà bạn quan tâm (thường là VARCHAR (MAX), VARBINARY (MAX), v.v.)
marc_s

1
Cảm ơn @marc_s, điều này rất hữu ích. Cột TableName cũng có thể bao gồm tên lược đồ vớiSELECT OBJECT_SCHEMA_NAME(i.object_id) + '.' + OBJECT_NAME(i.object_id) AS TableName, ...
CruiZen

2
Đó phải là kịch bản TSQL đẹp nhất tôi từng thấy
Agustin Meriles

2
Để bao gồm các chỉ mục NON-CLUSTERED, hãy xóa "và i.index_id <= 1" khỏi mệnh đề WHERE.
Gordon Bell

72

Trong SQL Server 2008, bạn cũng có thể chạy báo cáo tiêu chuẩn sử dụng đĩa theo bảng hàng đầu. Điều này có thể được tìm thấy bằng cách nhấp chuột phải vào DB, chọn Báo cáo-> Báo cáo chuẩn và chọn báo cáo bạn muốn.


8
Không đua đâu? Đó là một câu trả lời mang tính cách mạng. Cảm ơn đã đăng nó. (Không phải mỉa mai. Đã chạy các truy vấn này một cách thủ công được một thời gian và tôi không thể tin rằng các báo cáo này đã có sẵn!)
Jennifer Zouak

4

Truy vấn này giúp tìm bảng lớn nhất trong bạn đang kết nối.

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

Thật tốt khi có một cái gì đó mà chúng ta có thể dễ dàng ghi nhớ. Cảm ơn sự đồng nhất.
David Betz

3

Bạn cũng có thể sử dụng mã sau đây:

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

2

Nếu bạn đang sử dụng Sql Server Management Studio 2008, có một số trường dữ liệu nhất định bạn có thể xem trong cửa sổ chi tiết thám hiểm đối tượng. Đơn giản chỉ cần duyệt đến và chọn thư mục bảng. Trong chế độ xem chi tiết, bạn có thể nhấp chuột phải vào tiêu đề cột và thêm các trường vào "báo cáo". Số dặm của bạn có thể thay đổi nếu bạn đang trên SSMS 2008 express.


2

Tôi đã tìm thấy truy vấn này cũng rất hữu ích trong SqlServerCentral, đây là liên kết đến bài viết gốc

Máy chủ Sql bảng lớn nhất

  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   

Trong cơ sở dữ liệu của tôi, họ đã đưa ra các kết quả khác nhau giữa truy vấn này và câu trả lời đầu tiên.

Hy vọng ai đó thấy hữu ích


1

Câu trả lời của @ marc_s rất hay và tôi đã sử dụng nó được vài năm. Tuy nhiên, tôi nhận thấy rằng tập lệnh bỏ lỡ dữ liệu trong một số chỉ mục của cột và không hiển thị hình ảnh hoàn chỉnh. Ví dụ: khi bạn làm SUM(TotalSpace)ngược lại tập lệnh và so sánh nó với tổng thuộc tính cơ sở dữ liệu không gian trong Management Studio, các số không khớp trong trường hợp của tôi (Management Studio hiển thị số lớn hơn). Tôi đã sửa đổi tập lệnh để khắc phục vấn đề này và mở rộng nó ra một chút:

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

Hy vọng nó sẽ hữu ích cho một ai đó. Kịch bản này đã được thử nghiệm đối với các cơ sở dữ liệu lớn trên toàn TB với hàng trăm bảng, chỉ mục và lược đồ khác nhau.

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.