数据库健康检查需要覆盖连接状态、索引碎片、统计信息更新情况、存储空间使用率等多个核心维度,通过自定义存储过程可以把这些检查逻辑整合起来,同时还能对系统存储过程sp_updatestats的执行情况进行监控,及时发现统计信息更新异常的问题。

存储过程实现数据库健康检查的核心思路
自定义健康检查存储过程的核心是把分散的检查逻辑封装成统一的执行流程,同时记录每次检查的结果,方便后续排查问题。整体设计可以分为三个部分:基础健康指标检查、sp_updatestats执行监控、检查结果持久化。
基础健康指标检查项
需要覆盖的常规检查项包括:
- 数据库当前连接数是否正常
- 核心表的索引碎片率是否超过阈值
- 最近一次统计信息更新时间是否超过预设周期
- 数据文件和日志文件的使用率是否超过告警阈值
- 是否存在长时间运行的阻塞会话
sp_updatestats的监控价值
sp_updatestats是SQL Server提供的系统存储过程,用于更新数据库中所有用户定义表和内部表的统计信息。统计信息过期会导致查询优化器生成低效的执行计划,进而引发性能问题。监控sp_updatestats的执行状态、执行耗时、更新对象数量,能提前发现统计信息维护环节的异常。
自定义健康检查存储过程实现
以下是一个完整的自定义存储过程示例,整合了基础健康检查和sp_updatestats监控功能,适配SQL Server环境。
-- 创建数据库健康检查存储过程,同时监控sp_updatestats执行情况
CREATE PROCEDURE dbo.sp_DbHealthCheck
@MaxIndexFragmentRate FLOAT = 30.0, -- 索引碎片率告警阈值,默认30%
@MaxStatsUpdateDays INT = 7, -- 统计信息最大更新周期,默认7天
@MaxFileUsageRate FLOAT = 85.0 -- 文件使用率告警阈值,默认85%
AS
BEGIN
SET NOCOUNT ON;
-- 创建临时表存储检查结果
CREATE TABLE #HealthCheckResult (
CheckItem NVARCHAR(100),
CheckResult NVARCHAR(500),
IsAbnormal BIT,
CheckTime DATETIME DEFAULT GETDATE()
);
-- 1. 检查当前数据库连接数
DECLARE @CurrentConnections INT;
SELECT @CurrentConnections = COUNT(*) FROM sys.dm_exec_connections;
INSERT INTO #HealthCheckResult (CheckItem, CheckResult, IsAbnormal)
VALUES ('当前数据库连接数', '当前连接数:' + CAST(@CurrentConnections AS NVARCHAR(20)),
CASE WHEN @CurrentConnections > 500 THEN 1 ELSE 0 END);
-- 2. 检查核心表索引碎片率
INSERT INTO #HealthCheckResult (CheckItem, CheckResult, IsAbnormal)
SELECT
'索引碎片检查_' + OBJECT_NAME(ips.object_id),
'表:' + OBJECT_NAME(ips.object_id) + ',平均碎片率:' + CAST(ips.avg_fragmentation_in_percent AS NVARCHAR(20)) + '%',
CASE WHEN ips.avg_fragmentation_in_percent > @MaxIndexFragmentRate THEN 1 ELSE 0 END
FROM sys.dm_db_index_physical_stats(DB_ID(), NULL, NULL, NULL, 'LIMITED') ips
INNER JOIN sys.indexes i ON ips.object_id = i.object_id AND ips.index_id = i.index_id
WHERE OBJECT_NAME(ips.object_id) IN ('Orders', 'Users', 'Products'); -- 替换为实际核心表名
-- 3. 检查统计信息更新时间
INSERT INTO #HealthCheckResult (CheckItem, CheckResult, IsAbnormal)
SELECT
'统计信息更新检查_' + s.name + '.' + t.name,
'表:' + s.name + '.' + t.name + ',最近更新时间:' + CAST(stats_date(s.object_id, st.stats_id) AS NVARCHAR(30)),
CASE WHEN DATEDIFF(DAY, stats_date(s.object_id, st.stats_id), GETDATE()) > @MaxStatsUpdateDays THEN 1 ELSE 0 END
FROM sys.tables t
INNER JOIN sys.schemas s ON t.schema_id = s.schema_id
INNER JOIN sys.stats st ON t.object_id = st.object_id
WHERE t.name IN ('Orders', 'Users', 'Products'); -- 替换为实际核心表名
-- 4. 检查数据文件使用率
INSERT INTO #HealthCheckResult (CheckItem, CheckResult, IsAbnormal)
SELECT
'数据文件使用率_' + name,
'文件:' + name + ',使用率:' + CAST((size * 8.0 / 1024) / (max_size * 8.0 / 1024) * 100 AS NVARCHAR(20)) + '%',
CASE WHEN (size * 8.0 / 1024) / (max_size * 8.0 / 1024) * 100 > @MaxFileUsageRate THEN 1 ELSE 0 END
FROM sys.master_files
WHERE database_id = DB_ID() AND type = 0; -- 0代表数据文件
-- 5. 监控sp_updatestats执行过程
DECLARE @SpExecStartTime DATETIME = GETDATE();
DECLARE @UpdatedTables INT;
DECLARE @SpExecError NVARCHAR(500) = NULL;
BEGIN TRY
-- 执行sp_updatestats并记录更新数量
CREATE TABLE #SpUpdateStatsResult (
TableName NVARCHAR(200),
UpdatedRows INT
);
INSERT INTO #SpUpdateStatsResult
EXEC sp_updatestats;
SELECT @UpdatedTables = COUNT(*) FROM #SpUpdateStatsResult;
DROP TABLE #SpUpdateStatsResult;
END TRY
BEGIN CATCH
SET @SpExecError = ERROR_MESSAGE();
END CATCH
DECLARE @SpExecEndTime DATETIME = GETDATE();
DECLARE @SpExecDuration INT = DATEDIFF(SECOND, @SpExecStartTime, @SpExecEndTime);
-- 记录sp_updatestats监控结果
INSERT INTO #HealthCheckResult (CheckItem, CheckResult, IsAbnormal)
VALUES (
'sp_updatestats执行监控',
CASE WHEN @SpExecError IS NOT NULL THEN '执行失败,错误信息:' + @SpExecError
ELSE '执行成功,耗时:' + CAST(@SpExecDuration AS NVARCHAR(20)) + '秒,更新表数量:' + CAST(@UpdatedTables AS NVARCHAR(20)) END,
CASE WHEN @SpExecError IS NOT NULL OR @SpExecDuration > 300 THEN 1 ELSE 0 END -- 执行超过5分钟判定为异常
);
-- 输出所有检查结果
SELECT * FROM #HealthCheckResult;
-- 持久化检查结果到正式表,需提前创建dbo.DbHealthCheckLog表
INSERT INTO dbo.DbHealthCheckLog (CheckItem, CheckResult, IsAbnormal, CheckTime)
SELECT CheckItem, CheckResult, IsAbnormal, CheckTime FROM #HealthCheckResult;
DROP TABLE #HealthCheckResult;
END
GO
存储过程使用示例
创建完成存储过程后,可以直接执行以下语句触发健康检查:
-- 执行健康检查,使用默认阈值
EXEC dbo.sp_DbHealthCheck;
-- 自定义阈值执行检查
EXEC dbo.sp_DbHealthCheck
@MaxIndexFragmentRate = 25.0, -- 索引碎片率超过25%告警
@MaxStatsUpdateDays = 3, -- 统计信息超过3天未更新告警
@MaxFileUsageRate = 80.0; -- 文件使用率超过80%告警
注意事项
使用这个存储过程时需要注意几个问题:首先,执行sp_updatestats会对表加锁,建议在业务低峰期执行健康检查,避免影响正常业务;其次,示例中的核心表名需要根据实际业务场景替换,不要直接照搬;最后,持久化检查结果的日志表需要提前创建,表结构要和临时表#HealthCheckResult保持一致。
通过这种自定义存储过程的方式,不需要依赖额外的监控工具,就能实现数据库健康状态的定期巡检,同时还能对sp_updatestats的执行情况进行持续跟踪,及时发现统计信息维护环节的异常,保障数据库查询性能稳定。
存储过程数据库健康检查sp_updatestatsSQL_Server修改时间:2026-07-19 15:00:36