分析和清理SQL Server数据表和存储过程
生产环境有个SQL Server云数据库,花钱不少,性能却很差。最近发现跑一些并不太复杂的存储过程却需要好几分钟。其中一个常用的存储过程是将几张表通过一个键值关联并返回结果,这几张表都在千万级大小。分析了下执行计划,发现index seek花去了90%以上的时间,进而发现这些表的索引碎片化都极为严重。由于这个老DB几经易手,没人知道这些表和存储过程是做什么的,于是需要手动分析这些表的schema和存储过程所依赖的表。基于这些结果再对索引重建提升性能。下面就是用来分析DB的一些重要Query。
获取各表的磁盘使用量
SELECT
t.NAME AS TableName,
s.Name AS SchemaName,
p.rows AS RowCounts,
SUM(a.total_pages) * 8 / 1024 AS TotalSpaceMB,
SUM(a.used_pages) * 8 / 1024 AS UsedSpaceMB,
(SUM(a.total_pages) - SUM(a.used_pages)) * 8 /1024 AS UnusedSpaceMB
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 OUTER 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
GROUP BY
t.Name, s.Name, p.Rows
ORDER BY
UsedSpaceMB DESC
结果示例:
TableName | SchemaName | RowCounts | TotalSpaceMB | UsedSpaceMB | UnusedSpaceMB |
---|---|---|---|---|---|
T1 | dbo | 25609971 | 97735 | 97366 | 369 |
T2 | dbo | 157963374 | 76543 | 76341 | 201 |
T3 | dbo | 10714232 | 56383 | 53113 | 3269 |
T4 | dbo | 47533799 | 26000 | 25310 | 690 |
T5 | dbo | 15956528 | 17750 | 17742 | 8 |
获取各存储过程的用量
DECLARE @dbname varchar(30) = '';
select
db_name(st.dbid) as database_name,
object_name(st.objectid) as name,
p.size_in_bytes / 1024 as size_in_kb,
p.usecounts,
st.text
from sys.dm_exec_cached_plans p
cross apply sys.dm_exec_sql_text(p.plan_handle) st
where p.objtype = 'proc'
and st.dbid = db_id(@dbname)
order by p.usecounts desc
结果示例:
database_name | name | size_in_kb | usecounts | text |
---|---|---|---|---|
D | Proc_Upsert | 8800 | 39675743 | xxx |
D | Proc_Update | 1368 | 2216916 | xxx |
D | Proc_Select | 280 | 1641531 | xxx |
获取存储过程的上次执行时间
SELECT DB_NAME(database_id)
,OBJECT_NAME(object_id,database_id) as procname
,cached_time
,last_execution_time
,execution_count
FROM sys.dm_exec_procedure_stats
order by procname
结果示例:
procname | cached_time | last_execution_time | execution_count |
---|---|---|---|
CleanUpArticles | 2021-04-20 17:00:02.710 | 2021-04-20 17:00:02.710 | 3788 |
CleanUpTables | 2021-04-22 12:51:17.807 | 2021-04-22 12:51:17.807 | 6019 |
Proc_Select | 2021-04-19 02:09:41.830 | 2021-04-19 02:09:41.830 | 3827 |
获取存储过程依赖哪些表
SELECT DISTINCT p.name AS proc_name, t.name AS table_name
FROM sys.sql_dependencies d
INNER JOIN sys.procedures p ON p.object_id = d.object_id
INNER JOIN sys.tables t ON t.object_id = d.referenced_major_id
ORDER BY proc_name, table_name
结果示例:
proc_name | table_name |
---|---|
P1 | T1 |
P2 | T1 |
P2 | T2 |
分析各表索引的碎片化程度
Refer to: # Resolve index fragmentation by reorganizing or rebuilding indexes
DECLARE @dbname varchar(30) = '';
DECLARE @tablename varchar(30) = '';
SELECT a.object_id, object_name(a.object_id) AS TableName,
a.index_id, name AS IndedxName, avg_fragmentation_in_percent
FROM sys.dm_db_index_physical_stats
(DB_ID(@dbname)
, OBJECT_ID(@tablename)
, NULL
, NULL
, NULL) AS a
INNER JOIN sys.indexes AS b
ON a.object_id = b.object_id
AND a.index_id = b.index_id;
Sample result:
object_id | TableName | index_id | IndedxName | avg_fragmentation_in_percent |
---|---|---|---|---|
1733581214 | T1 | 1 | PK_dbo.T1 | 23.53719 |
1733581214 | T1 | 3 | key | 22.5999 |
重建索引
ALTER INDEX [PK_dbo.T1]
ON [dbo].[T1]
REBUILD WITH (ONLINE = ON);
重构索引
ALTER INDEX [PK_dbo.T1]
ON [dbo].[T1]
REORGANIZE;