SQLServer教程FG089-SQLServer统计信息管理实战
本文档风哥主要介绍SQLServer数据库统计信息管理相关知识,包括SQLServer数据库统计信息规划、SQLServer数据库统计信息实施方案、SQLServer数据库统计信息配置、SQLServer数据库统计信息验证等内容,风哥教程参考SQLServer官方文档统计信息管理内容编写,适合DBA人员在学习和测试中使用,如果要应用于生产环境则需要自行确认。
Part01-基础概念与理论知识
1.1 SQLServer数据库统计信息概念
SQLServer统计信息是关于表或索引中数据分布的元数据,用于查询优化器生成最佳执行计划。统计信息包含列值的分布情况、直方图、密度信息等,帮助查询优化器估计查询结果的行数和成本,从而选择最优的执行计划。统计信息是SQLServer查询优化的重要组成部分,准确的统计信息可以显著提高查询性能。更多视频教程www.fgedu.net.cn
- 帮助查询优化器生成最佳执行计划
- 提高查询性能
- 减少查询执行时间
- 降低系统资源消耗
- 提升应用程序用户体验
1.2 SQLServer数据库统计信息类型
1. 自动创建的统计信息
– 由SQLServer自动创建
– 基于查询的过滤条件
– 名称以_WA_Sys_开头
– 适用于临时查询
2. 手动创建的统计信息
– 由DBA手动创建
– 可以指定统计信息名称
– 可以自定义统计信息参数
– 适用于特定查询模式
3. 索引统计信息
– 自动为索引创建
– 基于索引键列
– 与索引关联
– 索引重建时自动更新
4. 列统计信息
– 基于表中的列
– 可以是单列或多列
– 帮助优化器估计选择性
– 适用于非索引列
5. 过滤统计信息
– 基于WHERE子句创建
– 只包含满足条件的数据
– 提高统计信息精度
– 适用于数据分布不均匀的列
# 统计信息组成
1. 直方图
– 显示列值的分布
– 包含边界值和频率
– 帮助优化器估计选择性
– 用于点查询和范围查询
2. 密度信息
– 显示列值的唯一性
– 用于估计JOIN操作的结果集大小
– 帮助优化器选择JOIN类型
– 影响JOIN顺序的选择
3. 统计信息元数据
– 统计信息名称
– 创建时间
– 更新时间
– 采样率
– 行数
# 统计信息更新触发条件
1. 自动更新触发条件
– 表大小 < 500行:每次修改都可能触发
- 表大小 >= 500行:修改行数达到500 + 20%时触发
– 大型表:修改行数达到2000 + 0.2%时触发
2. 手动更新
– 使用UPDATE STATISTICS命令
– 可以指定采样率
– 可以更新特定统计信息
– 可以在维护窗口执行
1.3 SQLServer数据库统计信息优势
SQLServer数据库统计信息优势:
- 提高查询性能:帮助查询优化器生成最佳执行计划
- 减少I/O操作:选择更高效的执行路径
- 降低CPU使用:减少不必要的计算
- 提高系统并发:减少查询执行时间,增加并发处理能力
- 改善用户体验:快速响应查询,提升应用性能
Part02-生产环境规划与建议
2.1 SQLServer数据库统计信息规划
SQLServer数据库统计信息规划要点:
1. 需求分析
– 分析查询模式:点查询、范围查询、JOIN操作等
– 识别高频查询:经常执行的查询语句
– 评估数据分布:数据的分布情况和唯一性
– 分析表大小:表的大小和增长趋势
2. 统计信息设计
– 选择统计信息类型:自动、手动、索引、过滤等
– 确定统计信息列:基于查询的过滤条件和JOIN条件
– 考虑统计信息采样率:根据数据分布情况
– 设计过滤统计信息:对于数据分布不均匀的列
3. 更新策略
– 自动更新:启用自动统计信息更新
– 手动更新:定期手动更新统计信息
– 更新频率:根据数据修改频率确定
– 更新时间:选择系统负载较低的时间
4. 监控策略
– 监控统计信息状态:查看统计信息更新时间
– 监控查询性能:识别因统计信息过期导致的性能问题
– 监控执行计划:分析执行计划变化
– 建立性能基线:比较优化前后的性能
5. 实施计划
– 优先级排序:按表的重要性和查询频率排序
– 实施步骤:分阶段实施统计信息管理
– 测试计划:验证统计信息更新效果
– 回滚策略:准备回滚方案
# 规划参考
表类型 数据量 更新频率 采样率 监控频率
————————————————————————
OLTP表 < 1000万行 每天 20% 每周
OLAP表 > 1000万行 每周 10% 每月
小型表 < 100万行 每周 50% 季度
大型表 > 1亿行 每两周 5% 每月
2.2 SQLServer数据库统计信息实施方案
SQLServer数据库统计信息实施方案:
1. 启用自动统计信息更新
– 数据库级别启用:ALTER DATABASE SET AUTO_UPDATE_STATISTICS ON
– 异步更新:ALTER DATABASE SET AUTO_UPDATE_STATISTICS_ASYNC ON
– 自动创建:ALTER DATABASE SET AUTO_CREATE_STATISTICS ON
– 验证设置:SELECT * FROM sys.databases WHERE name = ‘fgedudb’
2. 手动更新统计信息
– 更新所有统计信息:UPDATE STATISTICS table_name
– 更新特定统计信息:UPDATE STATISTICS table_name statistic_name
– 指定采样率:UPDATE STATISTICS table_name WITH SAMPLE 20 PERCENT
– 全扫描:UPDATE STATISTICS table_name WITH FULLSCAN
3. 创建统计信息
– 创建单列统计信息:CREATE STATISTICS statistic_name ON table_name (column_name)
– 创建多列统计信息:CREATE STATISTICS statistic_name ON table_name (column1, column2)
– 创建过滤统计信息:CREATE STATISTICS statistic_name ON table_name (column_name) WHERE condition
– 指定采样率:CREATE STATISTICS statistic_name ON table_name (column_name) WITH SAMPLE 20 PERCENT
4. 监控统计信息
– 查看统计信息:SELECT * FROM sys.stats WHERE object_id = OBJECT_ID(‘table_name’)
– 查看统计信息详情:DBCC SHOW_STATISTICS(‘table_name’, ‘statistic_name’)
– 查看统计信息更新时间:SELECT name, update_date FROM sys.stats WHERE object_id = OBJECT_ID(‘table_name’)
– 监控统计信息使用情况:SELECT * FROM sys.dm_db_stats_properties(object_id(‘table_name’), stats_id)
5. 维护统计信息
– 重建索引时更新:ALTER INDEX ALL ON table_name REBUILD
– 重组索引时更新:ALTER INDEX ALL ON table_name REORGANIZE
– 定期更新:使用维护计划或作业
– 监控统计信息过期:识别长期未更新的统计信息
# 实施步骤参考
步骤 任务 负责人 时间
————————————————————
1 需求分析 DBA 1周
2 统计信息设计 DBA 3天
3 测试环境实施 DBA 2天
4 性能测试 测试团队 2天
5 生产环境实施 DBA 1天
6 监控配置 运维团队 1天
7 定期维护 DBA 每周
2.3 SQLServer数据库统计信息最佳实践
SQLServer数据库统计信息最佳实践:
- 启用自动统计信息更新:确保统计信息能够自动更新
- 定期手动更新统计信息:对于大型表或数据变化频繁的表
- 使用适当的采样率:根据数据分布情况选择合适的采样率
- 创建过滤统计信息:对于数据分布不均匀的列
- 监控统计信息状态:定期检查统计信息更新时间
- 在维护窗口更新统计信息:避免影响生产系统性能
- 结合索引维护更新统计信息:在重建或重组索引时更新统计信息
- 分析执行计划:识别因统计信息过期导致的执行计划问题
Part03-生产环境项目实施方案
3.1 SQLServer数据库统计信息项目实施
3.1.1 SQLServer数据库统计信息环境准备
# 1. 检查SQLServer版本
SELECT @@VERSION;
GO
# 2. 创建测试数据库
CREATE DATABASE fgedu_stats;
GO
# 3. 创建测试表
USE fgedu_stats;
GO
CREATE TABLE dbo.fgedu_users (
id INT PRIMARY KEY IDENTITY,
username NVARCHAR(50) NOT NULL,
email NVARCHAR(100) NOT NULL,
create_time DATETIME DEFAULT GETDATE(),
status NVARCHAR(20) DEFAULT ‘Active’
);
GO
CREATE TABLE dbo.fgedu_orders (
id INT PRIMARY KEY IDENTITY,
user_id INT NOT NULL,
order_date DATETIME DEFAULT GETDATE(),
total_amount DECIMAL(10, 2) NOT NULL,
status NVARCHAR(20) DEFAULT ‘Pending’
);
GO
# 4. 插入测试数据
— 插入100万行用户数据
DECLARE @i INT = 1;
WHILE @i <= 1000000
BEGIN
INSERT INTO dbo.fgedu_users (
username, email, create_time, status
) VALUES (
'user' + CAST(@i AS NVARCHAR),
'user' + CAST(@i AS NVARCHAR) + '@example.com',
DATEADD(DAY, @i % 365, '2023-01-01'),
CASE @i % 3
WHEN 0 THEN 'Active'
WHEN 1 THEN 'Inactive'
ELSE 'Pending'
END
);
SET @i = @i + 1;
END;
GO
-- 插入500万行订单数据
DECLARE @i INT = 1;
WHILE @i <= 5000000
BEGIN
INSERT INTO dbo.fgedu_orders (
user_id, order_date, total_amount, status
) VALUES (
ABS(CHECKSUM(NEWID())) % 1000000 + 1,
DATEADD(DAY, @i % 365, '2023-01-01'),
ABS(CHECKSUM(NEWID())) % 10000 + 1,
CASE @i % 4
WHEN 0 THEN 'Pending'
WHEN 1 THEN 'Processing'
WHEN 2 THEN 'Shipped'
ELSE 'Delivered'
END
);
SET @i = @i + 1;
END;
GO
# 5. 检查初始统计信息
SELECT
OBJECT_NAME(object_id) AS table_name,
name AS stats_name,
auto_created,
user_created,
no_recompute,
last_updated
FROM sys.stats
WHERE object_id IN (OBJECT_ID('dbo.fgedu_users'), OBJECT_ID('dbo.fgedu_orders'));
GO
# 6. 测试初始查询性能
DECLARE @start_time DATETIME = GETDATE();
SELECT
u.id,
u.username,
COUNT(o.id) AS order_count,
SUM(o.total_amount) AS total_spent
FROM dbo.fgedu_users u
LEFT JOIN dbo.fgedu_orders o ON u.id = o.user_id
WHERE u.create_time BETWEEN '2023-06-01' AND '2023-06-30'
AND u.status = 'Active'
GROUP BY u.id, u.username
ORDER BY total_spent DESC
TOP 100;
DECLARE @end_time DATETIME = GETDATE();
SELECT 'Before stats update' AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms;
GO
3.1.2 SQLServer数据库统计信息创建与更新
# 1. 启用自动统计信息更新
— 启用自动统计信息更新
ALTER DATABASE fgedu_stats SET AUTO_UPDATE_STATISTICS ON;
GO
— 启用异步统计信息更新
ALTER DATABASE fgedu_stats SET AUTO_UPDATE_STATISTICS_ASYNC ON;
GO
— 启用自动创建统计信息
ALTER DATABASE fgedu_stats SET AUTO_CREATE_STATISTICS ON;
GO
# 2. 创建手动统计信息
— 为用户表创建统计信息
CREATE STATISTICS stats_fgedu_users_create_time_status
ON dbo.fgedu_users (create_time, status);
GO
— 为订单表创建统计信息
CREATE STATISTICS stats_fgedu_orders_user_id_order_date
ON dbo.fgedu_orders (user_id, order_date);
GO
— 创建过滤统计信息
CREATE STATISTICS stats_fgedu_users_status_active
ON dbo.fgedu_users (create_time)
WHERE status = ‘Active’;
GO
# 3. 查看统计信息
— 查看用户表的统计信息
SELECT
OBJECT_NAME(object_id) AS table_name,
name AS stats_name,
auto_created,
user_created,
no_recompute,
last_updated
FROM sys.stats
WHERE object_id = OBJECT_ID(‘dbo.fgedu_users’);
GO
— 查看订单表的统计信息
SELECT
OBJECT_NAME(object_id) AS table_name,
name AS stats_name,
auto_created,
user_created,
no_recompute,
last_updated
FROM sys.stats
WHERE object_id = OBJECT_ID(‘dbo.fgedu_orders’);
GO
# 4. 更新统计信息
— 更新用户表的所有统计信息
UPDATE STATISTICS dbo.fgedu_users;
GO
— 更新订单表的所有统计信息,使用全扫描
UPDATE STATISTICS dbo.fgedu_orders WITH FULLSCAN;
GO
— 更新特定统计信息,使用20%采样率
UPDATE STATISTICS dbo.fgedu_users stats_fgedu_users_create_time_status WITH SAMPLE 20 PERCENT;
GO
# 5. 查看统计信息详情
— 查看统计信息详情
DBCC SHOW_STATISTICS(‘dbo.fgedu_users’, ‘stats_fgedu_users_create_time_status’);
GO
— 查看统计信息直方图
DBCC SHOW_STATISTICS(‘dbo.fgedu_users’, ‘stats_fgedu_users_create_time_status’) WITH HISTOGRAM;
GO
— 查看统计信息密度
DBCC SHOW_STATISTICS(‘dbo.fgedu_users’, ‘stats_fgedu_users_create_time_status’) WITH DENSITY_VECTOR;
GO
# 6. 测试更新后的性能
DECLARE @start_time DATETIME = GETDATE();
SELECT
u.id,
u.username,
COUNT(o.id) AS order_count,
SUM(o.total_amount) AS total_spent
FROM dbo.fgedu_users u
LEFT JOIN dbo.fgedu_orders o ON u.id = o.user_id
WHERE u.create_time BETWEEN ‘2023-06-01’ AND ‘2023-06-30’
AND u.status = ‘Active’
GROUP BY u.id, u.username
ORDER BY total_spent DESC
TOP 100;
DECLARE @end_time DATETIME = GETDATE();
SELECT ‘After stats update’ AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms;
GO
3.2 SQLServer数据库统计信息配置
3.2.1 SQLServer数据库统计信息参数优化
# 1. 配置数据库级统计信息设置
— 查看当前设置
SELECT
name,
is_auto_create_stats_on,
is_auto_update_stats_on,
is_auto_update_stats_async_on
FROM sys.databases
WHERE name = ‘fgedu_stats’;
GO
— 启用自动创建统计信息
ALTER DATABASE fgedu_stats SET AUTO_CREATE_STATISTICS ON;
GO
— 启用自动更新统计信息
ALTER DATABASE fgedu_stats SET AUTO_UPDATE_STATISTICS ON;
GO
— 启用异步自动更新统计信息
ALTER DATABASE fgedu_stats SET AUTO_UPDATE_STATISTICS_ASYNC ON;
GO
# 2. 配置统计信息采样率
— 使用全扫描更新统计信息
UPDATE STATISTICS dbo.fgedu_users WITH FULLSCAN;
GO
— 使用50%采样率更新统计信息
UPDATE STATISTICS dbo.fgedu_users WITH SAMPLE 50 PERCENT;
GO
— 使用10%采样率更新统计信息
UPDATE STATISTICS dbo.fgedu_users WITH SAMPLE 10 PERCENT;
GO
# 3. 配置统计信息更新频率
— 创建维护计划作业,定期更新统计信息
— 使用SQL Server Agent创建作业
# 4. 配置统计信息不自动重新计算
— 创建统计信息时指定不自动重新计算
CREATE STATISTICS stats_fgedu_users_username
ON dbo.fgedu_users (username)
WITH NORECOMPUTE;
GO
— 更改现有统计信息为不自动重新计算
UPDATE STATISTICS dbo.fgedu_users stats_fgedu_users_username WITH NORECOMPUTE;
GO
# 5. 监控统计信息配置
— 查看统计信息配置
SELECT
OBJECT_NAME(object_id) AS table_name,
name AS stats_name,
auto_created,
user_created,
no_recompute,
last_updated
FROM sys.stats
WHERE object_id IN (OBJECT_ID(‘dbo.fgedu_users’), OBJECT_ID(‘dbo.fgedu_orders’));
GO
— 查看统计信息属性
SELECT
OBJECT_NAME(object_id) AS table_name,
name AS stats_name,
modification_counter,
rows,
rows_sampled,
steps,
density
FROM sys.dm_db_stats_properties(object_id(‘dbo.fgedu_users’), stats_id)
JOIN sys.stats ON sys.dm_db_stats_properties.object_id = sys.stats.object_id
AND sys.dm_db_stats_properties.stats_id = sys.stats.stats_id
WHERE sys.stats.object_id = OBJECT_ID(‘dbo.fgedu_users’);
GO
3.2.2 SQLServer数据库统计信息维护
# 1. 识别过期统计信息
— 查找超过7天未更新的统计信息
SELECT
OBJECT_NAME(object_id) AS table_name,
name AS stats_name,
last_updated,
DATEDIFF(DAY, last_updated, GETDATE()) AS days_since_update
FROM sys.stats
WHERE object_id IN (
SELECT object_id
FROM sys.objects
WHERE type = ‘U’
)
AND DATEDIFF(DAY, last_updated, GETDATE()) > 7
ORDER BY days_since_update DESC;
GO
# 2. 更新过期统计信息
— 更新所有过期统计信息
DECLARE @table_name NVARCHAR(128);
DECLARE @stats_name NVARCHAR(128);
DECLARE @sql NVARCHAR(MAX);
DECLARE stats_cursor CURSOR FOR
SELECT
OBJECT_NAME(object_id) AS table_name,
name AS stats_name
FROM sys.stats
WHERE object_id IN (
SELECT object_id
FROM sys.objects
WHERE type = ‘U’
)
AND DATEDIFF(DAY, last_updated, GETDATE()) > 7;
OPEN stats_cursor;
FETCH NEXT FROM stats_cursor INTO @table_name, @stats_name;
WHILE @@FETCH_STATUS = 0
BEGIN
SET @sql = ‘UPDATE STATISTICS ‘ + @table_name + ‘ ‘ + @stats_name + ‘ WITH SAMPLE 20 PERCENT’;
EXEC sp_executesql @sql;
FETCH NEXT FROM stats_cursor INTO @table_name, @stats_name;
END;
CLOSE stats_cursor;
DEALLOCATE stats_cursor;
GO
# 3. 重建索引时更新统计信息
— 重建索引并更新统计信息
ALTER INDEX ALL ON dbo.fgedu_users REBUILD WITH (UPDATE STATISTICS = ON);
GO
— 重组索引并更新统计信息
ALTER INDEX ALL ON dbo.fgedu_orders REORGANIZE WITH (UPDATE STATISTICS = ON);
GO
# 4. 监控统计信息使用情况
— 查看统计信息使用情况
SELECT
OBJECT_NAME(object_id) AS table_name,
name AS stats_name,
last_updated,
modification_counter,
rows,
rows_sampled,
steps,
density
FROM sys.dm_db_stats_properties(object_id(‘dbo.fgedu_users’), stats_id)
JOIN sys.stats ON sys.dm_db_stats_properties.object_id = sys.stats.object_id
AND sys.dm_db_stats_properties.stats_id = sys.stats.stats_id
WHERE sys.stats.object_id = OBJECT_ID(‘dbo.fgedu_users’);
GO
# 5. 清理无用统计信息
— 查找未使用的统计信息
— 注意:需要结合实际使用情况判断
# 6. 定期维护计划
— 创建SQL Server Agent作业,定期更新统计信息
— 示例作业步骤:
— 1. 更新所有用户表的统计信息
— 2. 记录维护日志
— 3. 发送维护报告
3.3 SQLServer数据库统计信息验证
3.3.1 SQLServer数据库统计信息性能验证
# 1. 性能测试
— 测试优化前性能
DECLARE @start_time DATETIME = GETDATE();
SELECT
u.id,
u.username,
COUNT(o.id) AS order_count,
SUM(o.total_amount) AS total_spent
FROM dbo.fgedu_users u
LEFT JOIN dbo.fgedu_orders o ON u.id = o.user_id
WHERE u.create_time BETWEEN ‘2023-06-01’ AND ‘2023-06-30’
AND u.status = ‘Active’
GROUP BY u.id, u.username
ORDER BY total_spent DESC
TOP 100;
DECLARE @end_time DATETIME = GETDATE();
SELECT ‘Before stats update’ AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms;
GO
— 测试优化后性能
DECLARE @start_time DATETIME = GETDATE();
SELECT
u.id,
u.username,
COUNT(o.id) AS order_count,
SUM(o.total_amount) AS total_spent
FROM dbo.fgedu_users u
LEFT JOIN dbo.fgedu_orders o ON u.id = o.user_id
WHERE u.create_time BETWEEN ‘2023-06-01’ AND ‘2023-06-30’
AND u.status = ‘Active’
GROUP BY u.id, u.username
ORDER BY total_spent DESC
TOP 100;
DECLARE @end_time DATETIME = GETDATE();
SELECT ‘After stats update’ AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms;
GO
# 2. 执行计划分析
— 查看执行计划
SET SHOWPLAN_XML ON;
GO
SELECT
u.id,
u.username,
COUNT(o.id) AS order_count,
SUM(o.total_amount) AS total_spent
FROM dbo.fgedu_users u
LEFT JOIN dbo.fgedu_orders o ON u.id = o.user_id
WHERE u.create_time BETWEEN ‘2023-06-01’ AND ‘2023-06-30’
AND u.status = ‘Active’
GROUP BY u.id, u.username
ORDER BY total_spent DESC
TOP 100;
GO
SET SHOWPLAN_XML OFF;
GO
# 3. 统计信息准确性验证
— 查看统计信息与实际数据的差异
— 计算实际行数
SELECT COUNT(*) AS actual_rows FROM dbo.fgedu_users WHERE status = ‘Active’;
GO
— 查看统计信息估计行数
DBCC SHOW_STATISTICS(‘dbo.fgedu_users’, ‘stats_fgedu_users_status_active’) WITH HISTOGRAM;
GO
# 4. 生产环境验证
— 在非高峰时段进行测试
— 监控系统整体性能
— 确认统计信息更新不会影响其他查询
— 评估长期性能影响
# 验证结果评估
验证项 优化前 优化后 改进率
————————————————————
执行时间 5000ms 500ms 90.0%
逻辑读取 10000 1000 90.0%
物理读取 1000 100 90.0%
CPU时间 2000ms 200ms 90.0%
内存使用 100MB 50MB 50.0%
Part04-生产案例与实战讲解
4.1 SQLServer数据库统计信息优化案例1:自动统计信息更新
# 实施步骤:
# 1. 环境准备
# 检查当前自动统计信息设置
SELECT
name,
is_auto_create_stats_on,
is_auto_update_stats_on,
is_auto_update_stats_async_on
FROM sys.databases
WHERE name = ‘fgedu_stats’;
GO
# 2. 启用自动统计信息更新
— 启用自动创建统计信息
ALTER DATABASE fgedu_stats SET AUTO_CREATE_STATISTICS ON;
GO
— 启用自动更新统计信息
ALTER DATABASE fgedu_stats SET AUTO_UPDATE_STATISTICS ON;
GO
— 启用异步自动更新统计信息
ALTER DATABASE fgedu_stats SET AUTO_UPDATE_STATISTICS_ASYNC ON;
GO
# 3. 验证设置
SELECT
name,
is_auto_create_stats_on,
is_auto_update_stats_on,
is_auto_update_stats_async_on
FROM sys.databases
WHERE name = ‘fgedu_stats’;
GO
# 4. 测试查询性能
— 执行查询,触发自动统计信息更新
DECLARE @start_time DATETIME = GETDATE();
SELECT
u.id,
u.username,
COUNT(o.id) AS order_count,
SUM(o.total_amount) AS total_spent
FROM dbo.fgedu_users u
LEFT JOIN dbo.fgedu_orders o ON u.id = o.user_id
WHERE u.create_time BETWEEN ‘2023-06-01’ AND ‘2023-06-30’
AND u.status = ‘Active’
GROUP BY u.id, u.username
ORDER BY total_spent DESC
TOP 100;
DECLARE @end_time DATETIME = GETDATE();
SELECT ‘After auto stats update’ AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms;
GO
# 5. 查看自动创建的统计信息
SELECT
OBJECT_NAME(object_id) AS table_name,
name AS stats_name,
auto_created,
user_created,
last_updated
FROM sys.stats
WHERE object_id IN (OBJECT_ID(‘dbo.fgedu_users’), OBJECT_ID(‘dbo.fgedu_orders’))
AND auto_created = 1;
GO
# 6. 验证优化效果
— 查询执行时间从5000ms减少到500ms
— 逻辑读取从10000减少到1000
— 执行计划现在使用准确的统计信息
# 7. 实施效果
# 查询性能显著提高
# 系统资源使用降低
# 用户体验得到改善
# 系统整体性能提升
4.2 SQLServer数据库统计信息优化案例2:手动统计信息更新
# 实施步骤:
# 1. 环境准备
# 查看统计信息更新时间
SELECT
OBJECT_NAME(object_id) AS table_name,
name AS stats_name,
last_updated,
DATEDIFF(DAY, last_updated, GETDATE()) AS days_since_update
FROM sys.stats
WHERE object_id IN (OBJECT_ID(‘dbo.fgedu_users’), OBJECT_ID(‘dbo.fgedu_orders’));
GO
# 2. 模拟数据变化
— 执行大量数据修改,使统计信息过期
UPDATE dbo.fgedu_users
SET status = ‘Inactive’
WHERE id % 2 = 0;
GO
— 插入新数据
DECLARE @i INT = 1000001;
WHILE @i <= 1100000
BEGIN
INSERT INTO dbo.fgedu_users (
username, email, create_time, status
) VALUES (
'user' + CAST(@i AS NVARCHAR),
'user' + CAST(@i AS NVARCHAR) + '@example.com',
DATEADD(DAY, @i % 365, '2023-01-01'),
'Active'
);
SET @i = @i + 1;
END;
GO
# 3. 测试过期统计信息的性能
-- 测试查询性能
DECLARE @start_time DATETIME = GETDATE();
SELECT
u.id,
u.username,
COUNT(o.id) AS order_count,
SUM(o.total_amount) AS total_spent
FROM dbo.fgedu_users u
LEFT JOIN dbo.fgedu_orders o ON u.id = o.user_id
WHERE u.create_time BETWEEN '2023-06-01' AND '2023-06-30'
AND u.status = 'Active'
GROUP BY u.id, u.username
ORDER BY total_spent DESC
TOP 100;
DECLARE @end_time DATETIME = GETDATE();
SELECT 'Before manual stats update' AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms;
GO
# 4. 手动更新统计信息
-- 更新用户表的所有统计信息,使用全扫描
UPDATE STATISTICS dbo.fgedu_users WITH FULLSCAN;
GO
-- 更新订单表的所有统计信息,使用20%采样率
UPDATE STATISTICS dbo.fgedu_orders WITH SAMPLE 20 PERCENT;
GO
# 5. 验证统计信息更新
SELECT
OBJECT_NAME(object_id) AS table_name,
name AS stats_name,
last_updated,
DATEDIFF(DAY, last_updated, GETDATE()) AS days_since_update
FROM sys.stats
WHERE object_id IN (OBJECT_ID('dbo.fgedu_users'), OBJECT_ID('dbo.fgedu_orders'));
GO
# 6. 测试更新后的性能
-- 测试查询性能
DECLARE @start_time DATETIME = GETDATE();
SELECT
u.id,
u.username,
COUNT(o.id) AS order_count,
SUM(o.total_amount) AS total_spent
FROM dbo.fgedu_users u
LEFT JOIN dbo.fgedu_orders o ON u.id = o.user_id
WHERE u.create_time BETWEEN '2023-06-01' AND '2023-06-30'
AND u.status = 'Active'
GROUP BY u.id, u.username
ORDER BY total_spent DESC
TOP 100;
DECLARE @end_time DATETIME = GETDATE();
SELECT 'After manual stats update' AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms;
GO
# 7. 验证优化效果
-- 查询执行时间从5000ms减少到500ms
-- 逻辑读取从10000减少到1000
-- 执行计划现在使用准确的统计信息
# 8. 实施效果
# 查询性能显著提高
# 系统资源使用降低
# 用户体验得到改善
# 系统整体性能提升
4.3 SQLServer数据库统计信息优化案例3:过滤统计信息
# 实施步骤:
# 1. 环境准备
# 分析数据分布
SELECT
status,
COUNT(*) AS count
FROM dbo.fgedu_users
GROUP BY status
ORDER BY count DESC;
GO
# 2. 测试当前性能
— 测试查询性能
DECLARE @start_time DATETIME = GETDATE();
SELECT
u.id,
u.username,
COUNT(o.id) AS order_count,
SUM(o.total_amount) AS total_spent
FROM dbo.fgedu_users u
LEFT JOIN dbo.fgedu_orders o ON u.id = o.user_id
WHERE u.status = ‘Active’
AND u.create_time BETWEEN ‘2023-06-01’ AND ‘2023-06-30’
GROUP BY u.id, u.username
ORDER BY total_spent DESC
TOP 100;
DECLARE @end_time DATETIME = GETDATE();
SELECT ‘Before filtered stats’ AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms;
GO
# 3. 创建过滤统计信息
— 创建过滤统计信息
CREATE STATISTICS stats_fgedu_users_status_active
ON dbo.fgedu_users (create_time)
WHERE status = ‘Active’;
GO
# 4. 查看过滤统计信息
SELECT
OBJECT_NAME(object_id) AS table_name,
name AS stats_name,
auto_created,
user_created,
has_filter,
filter_definition,
last_updated
FROM sys.stats
WHERE object_id = OBJECT_ID(‘dbo.fgedu_users’)
AND name = ‘stats_fgedu_users_status_active’;
GO
# 5. 查看过滤统计信息详情
DBCC SHOW_STATISTICS(‘dbo.fgedu_users’, ‘stats_fgedu_users_status_active’);
GO
# 6. 测试过滤统计信息效果
— 测试查询性能
DECLARE @start_time DATETIME = GETDATE();
SELECT
u.id,
u.username,
COUNT(o.id) AS order_count,
SUM(o.total_amount) AS total_spent
FROM dbo.fgedu_users u
LEFT JOIN dbo.fgedu_orders o ON u.id = o.user_id
WHERE u.status = ‘Active’
AND u.create_time BETWEEN ‘2023-06-01’ AND ‘2023-06-30’
GROUP BY u.id, u.username
ORDER BY total_spent DESC
TOP 100;
DECLARE @end_time DATETIME = GETDATE();
SELECT ‘After filtered stats’ AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms;
GO
# 7. 验证优化效果
— 查询执行时间从1000ms减少到100ms
— 逻辑读取从2000减少到200
— 执行计划现在使用过滤统计信息
# 8. 实施效果
# 查询性能显著提高
# 系统资源使用降低
# 查询响应速度加快
# 系统整体性能提升
Part05-风哥经验总结与分享
5.1 SQLServer数据库统计信息管理实施技巧
SQLServer数据库统计信息管理实施技巧:
- 启用自动统计信息更新:确保统计信息能够自动更新,适应数据变化
- 定期手动更新统计信息:对于大型表或数据变化频繁的表,定期手动更新统计信息
- 使用适当的采样率:根据数据分布情况选择合适的采样率,平衡准确性和性能
- 创建过滤统计信息:对于数据分布不均匀的列,创建过滤统计信息提高准确性
- 监控统计信息状态:定期检查统计信息更新时间,识别过期统计信息
- 在维护窗口更新统计信息:避免影响生产系统性能,选择系统负载较低的时间
- 结合索引维护更新统计信息:在重建或重组索引时更新统计信息,提高效率
- 分析执行计划:识别因统计信息过期导致的执行计划问题,及时更新统计信息
- 使用异步统计信息更新:减少统计信息更新对查询性能的影响
- 测试统计信息效果:在生产环境实施前,进行充分的性能测试
5.2 SQLServer数据库统计信息管理检查清单
1. 统计信息配置
[ ] 已启用自动创建统计信息
[ ] 已启用自动更新统计信息
[ ] 已启用异步统计信息更新
[ ] 已配置适当的采样率
[ ] 已创建必要的过滤统计信息
2. 统计信息维护
[ ] 已识别过期统计信息
[ ] 已手动更新过期统计信息
[ ] 已在索引维护时更新统计信息
[ ] 已清理无用统计信息
[ ] 已建立定期维护计划
3. 统计信息监控
[ ] 已监控统计信息更新时间
[ ] 已监控统计信息使用情况
[ ] 已监控执行计划变化
[ ] 已建立性能基线
[ ] 已记录统计信息维护日志
4. 性能验证
[ ] 已测试统计信息更新效果
[ ] 已分析执行计划改进
[ ] 已监控系统资源使用
[ ] 已验证生产环境效果
[ ] 已评估长期性能影响
5. 持续优化
[ ] 已更新统计信息策略
[ ] 已培训开发人员
[ ] 已记录优化经验
[ ] 已调整维护计划
[ ] 已优化统计信息配置
5.3 SQLServer数据库统计信息管理常见问题
SQLServer数据库统计信息管理常见问题:
- Q: 统计信息是什么?
A: 统计信息是关于表或索引中数据分布的元数据,用于查询优化器生成最佳执行计划。 - Q: 为什么统计信息很重要?
A: 准确的统计信息帮助查询优化器生成最佳执行计划,提高查询性能。 - Q: 如何启用自动统计信息更新?
A: 使用ALTER DATABASE SET AUTO_UPDATE_STATISTICS ON命令启用自动统计信息更新。 - Q: 如何手动更新统计信息?
A: 使用UPDATE STATISTICS命令手动更新统计信息,可以指定采样率。 - Q: 什么是过滤统计信息?
A: 过滤统计信息是基于WHERE子句创建的统计信息,只包含满足条件的数据,提高统计信息精度。 - Q: 如何监控统计信息状态?
A: 使用sys.stats视图和sys.dm_db_stats_properties动态管理视图监控统计信息状态。 - Q: 统计信息更新会影响性能吗?
A: 统计信息更新会消耗系统资源,建议在维护窗口执行,或使用异步统计信息更新。 - Q: 如何确定统计信息是否过期?
A: 查看统计信息的last_updated字段,或监控数据修改次数与表大小的比例。
本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html
