1. 首页 > SQLServer教程 > 正文

SQLServer教程FG087-SQLServer查询性能调优实战

本文档风哥主要介绍SQLServer数据库查询性能调优相关知识,包括SQLServer数据库查询性能调优规划、SQLServer数据库查询性能调优实施方案、SQLServer数据库查询性能调优配置、SQLServer数据库查询性能调优验证等内容,风哥教程参考SQLServer官方文档查询性能调优内容编写,适合DBA人员在学习和测试中使用,如果要应用于生产环境则需要自行确认。

Part01-基础概念与理论知识

1.1 SQLServer数据库查询性能调优概念

SQLServer查询性能调优是指通过各种技术和方法优化SQL查询的执行效率,减少查询响应时间,提高系统整体性能。查询性能调优是SQLServer数据库管理的重要组成部分,直接影响应用程序的用户体验和系统的可扩展性。查询性能调优涉及查询语句优化、索引设计、统计信息管理、执行计划分析等多个方面。更多视频教程www.fgedu.net.cn

SQLServer数据库查询性能调优的重要性:

  • 提高查询响应速度
  • 减少系统资源消耗
  • 提升应用程序用户体验
  • 增加系统并发处理能力
  • 降低硬件成本

1.2 SQLServer数据库查询性能调优组件

# SQLServer数据库查询性能调优组件

1. 查询语句优化
– SQL语句结构优化
– 避免全表扫描
– 使用合适的JOIN类型
– 减少子查询使用

2. 索引设计与优化
– 聚集索引设计
– 非聚集索引设计
– 覆盖索引使用
– 索引维护

3. 统计信息管理
– 统计信息更新
– 统计信息精度
– 自动统计信息管理
– 手动统计信息更新

4. 执行计划分析
– 执行计划查看
– 执行计划解读
– 执行计划缓存
– 执行计划选择

5. 服务器配置优化
– 内存配置
– 并行度配置
– 最大并行度设置
– 查询超时设置

6. 存储优化
– 数据文件布局
– 存储子系统性能
– 分区表使用
– 数据压缩

# 查询性能调优流程

1. 识别慢查询
– 使用DMV监控
– 使用SQL Server Profiler
– 使用Extended Events
– 分析应用程序日志

2. 分析执行计划
– 查看估计执行计划
– 查看实际执行计划
– 分析执行计划运算符
– 识别性能瓶颈

3. 优化查询语句
– 重写SQL语句
– 调整JOIN顺序
– 使用适当的索引
– 避免昂贵的运算符

4. 优化索引
– 添加缺失索引
– 删除冗余索引
– 重建碎片化索引
– 调整索引填充因子

5. 优化统计信息
– 更新统计信息
– 调整统计信息采样率
– 使用过滤统计信息
– 监控统计信息状态

6. 验证优化效果
– 测试查询性能
– 监控系统资源使用
– 评估优化前后对比
– 确认生产环境效果

1.3 SQLServer数据库查询性能调优优势

SQLServer数据库查询性能调优优势:

  • 提高查询速度:显著减少查询响应时间,提升用户体验
  • 降低资源消耗:减少CPU、内存和I/O使用,提高系统整体性能
  • 增加并发处理:支持更多用户同时访问,提高系统可扩展性
  • 降低硬件成本:通过优化充分利用现有硬件资源,减少硬件升级需求
  • 提高数据可靠性:减少系统负载,降低系统故障风险
  • 简化管理:通过优化减少维护工作量,提高管理效率
风哥提示:查询性能调优是SQLServer数据库管理的核心任务之一,建议定期进行查询性能分析和优化,以确保系统的高效运行。学习交流加群风哥微信: itpux-com

Part02-生产环境规划与建议

2.1 SQLServer数据库查询性能调优规划

SQLServer数据库查询性能调优规划要点:

# 查询性能调优规划步骤

1. 需求分析
– 确定性能目标:响应时间、吞吐量
– 分析应用程序查询模式
– 评估系统资源使用情况
– 识别性能瓶颈

2. 监控策略
– 建立监控系统:DMV、Profiler、Extended Events
– 定义性能基线
– 设置告警阈值
– 定期性能报告

3. 优化策略
– 短期优化:快速解决慢查询
– 中期优化:索引和统计信息优化
– 长期优化:架构和设计优化
– 持续优化:定期审查和调整

4. 资源规划
– 硬件资源:CPU、内存、存储
– 人力资源:DBA、开发人员
– 时间资源:优化窗口、测试时间
– 工具资源:监控和分析工具

5. 测试计划
– 性能测试:基准测试、负载测试
– 回归测试:确保优化不影响功能
– 生产环境测试:在非高峰时段测试
– 测试结果分析:评估优化效果

# 规划参考

应用类型 性能目标 监控频率 优化频率 资源需求
————————————————————————
OLTP系统 < 100ms 实时 每周 高 OLAP系统 < 5s 每日 每月 中 混合系统 < 500ms 每小时 每两周 中 小型应用 < 2s 每日 季度 低

2.2 SQLServer数据库查询性能调优实施方案

SQLServer数据库查询性能调优实施方案:

# 查询性能调优实施方案

1. 慢查询识别与分析
– 使用DMV识别慢查询
– 分析执行计划
– 识别性能瓶颈
– 优先级排序

2. 查询语句优化
– 重写SQL语句
– 调整JOIN顺序
– 使用适当的索引
– 避免昂贵的运算符

3. 索引优化
– 添加缺失索引
– 删除冗余索引
– 重建碎片化索引
– 调整索引填充因子

4. 统计信息优化
– 更新统计信息
– 调整统计信息采样率
– 使用过滤统计信息
– 监控统计信息状态

5. 服务器配置优化
– 内存配置调整
– 并行度设置
– 查询超时设置
– 其他服务器参数调整

6. 存储优化
– 数据文件布局调整
– 存储子系统优化
– 分区表使用
– 数据压缩

# 实施步骤参考

步骤 任务 负责人 时间
————————————————————
1 慢查询识别 DBA 1天
2 执行计划分析 DBA 2天
3 查询语句优化 开发人员 3天
4 索引优化 DBA 2天
5 统计信息优化 DBA 1天
6 服务器配置调整 DBA 1天
7 性能测试 测试团队 2天
8 生产环境实施 DBA 1天

2.3 SQLServer数据库查询性能调优最佳实践

SQLServer数据库查询性能调优最佳实践:

  • 定期监控:建立性能监控系统,定期分析慢查询
  • 使用参数化查询:减少执行计划缓存膨胀,提高缓存命中率
  • 优化索引:为频繁查询的列创建适当的索引,避免过度索引
  • 更新统计信息:定期更新统计信息,确保查询优化器生成准确的执行计划
  • 避免全表扫描:使用索引覆盖查询,减少I/O操作
  • 优化JOIN操作:使用适当的JOIN类型,调整JOIN顺序
  • 使用分区表:对于大型表,使用分区表提高查询性能
  • 监控执行计划:定期分析执行计划,识别性能问题
生产环境建议:查询性能调优应根据系统的实际情况进行调整,建议在实施前进行充分测试,确保不会对系统性能造成负面影响。学习交流加群风哥QQ113257174

Part03-生产环境项目实施方案

3.1 SQLServer数据库查询性能调优项目实施

3.1.1 SQLServer数据库慢查询识别

# 慢查询识别步骤

# 1. 使用DMV识别慢查询
— 查找执行时间最长的查询
SELECT
TOP 10
qs.total_elapsed_time / 1000000.0 AS total_elapsed_time_sec,
qs.execution_count,
qs.total_elapsed_time / qs.execution_count / 1000000.0 AS avg_elapsed_time_sec,
SUBSTRING(qt.text, qs.statement_start_offset / 2 + 1,
(CASE WHEN qs.statement_end_offset = -1
THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
ELSE qs.statement_end_offset
END – qs.statement_start_offset) / 2) AS query_text
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
ORDER BY qs.total_elapsed_time DESC;
GO

— 查找逻辑读取最多的查询
SELECT
TOP 10
qs.total_logical_reads,
qs.execution_count,
qs.total_logical_reads / qs.execution_count AS avg_logical_reads,
SUBSTRING(qt.text, qs.statement_start_offset / 2 + 1,
(CASE WHEN qs.statement_end_offset = -1
THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
ELSE qs.statement_end_offset
END – qs.statement_start_offset) / 2) AS query_text
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
ORDER BY qs.total_logical_reads DESC;
GO

— 查找物理读取最多的查询
SELECT
TOP 10
qs.total_physical_reads,
qs.execution_count,
qs.total_physical_reads / qs.execution_count AS avg_physical_reads,
SUBSTRING(qt.text, qs.statement_start_offset / 2 + 1,
(CASE WHEN qs.statement_end_offset = -1
THEN LEN(CONVERT(NVARCHAR(MAX), qt.text)) * 2
ELSE qs.statement_end_offset
END – qs.statement_start_offset) / 2) AS query_text
FROM sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) qt
ORDER BY qs.total_physical_reads DESC;
GO

# 2. 使用SQL Server Profiler识别慢查询
— 启动SQL Server Profiler
— 创建跟踪,选择事件:RPC:Completed, SQL:BatchCompleted
— 设置筛选器:Duration > 1000ms
— 运行跟踪,收集慢查询

# 3. 使用Extended Events识别慢查询
— 创建Extended Events会话
CREATE EVENT SESSION [SlowQueries] ON SERVER
ADD EVENT sqlserver.rpc_completed(
ACTION(sqlserver.database_name,sqlserver.sql_text,sqlserver.username)
WHERE ([duration]>(1000000))),
ADD EVENT sqlserver.sql_batch_completed(
ACTION(sqlserver.database_name,sqlserver.sql_text,sqlserver.username)
WHERE ([duration]>(1000000)))
ADD TARGET package0.event_file(
SET filename=N’/sqlserver/fgdata/SlowQueries.xel’,max_file_size=(50),max_rollover_files=(5))
WITH (MAX_MEMORY=4096 KB,EVENT_RETENTION_MODE=ALLOW_SINGLE_EVENT_LOSS,MAX_DISPATCH_LATENCY=30 SECONDS,MAX_EVENT_SIZE=0 KB,MEMORY_PARTITION_MODE=NONE,TRACK_CAUSALITY=OFF,STARTUP_STATE=OFF);
GO

— 启动会话
ALTER EVENT SESSION [SlowQueries] ON SERVER STATE = START;
GO

— 查看收集的慢查询
SELECT
event_data = CONVERT(xml, event_data)
FROM sys.fn_xe_file_target_read_file(‘/sqlserver/fgdata/SlowQueries*.xel’, NULL, NULL, NULL);
GO

3.1.2 SQLServer数据库执行计划分析

# 执行计划分析步骤

# 1. 查看估计执行计划
— 在SSMS中,选中查询,按Ctrl+L查看估计执行计划
— 或使用SET SHOWPLAN_XML ON
SET SHOWPLAN_XML ON;
GO

SELECT
*
FROM dbo.fgedu_users
WHERE username = ‘user1’;
GO

SET SHOWPLAN_XML OFF;
GO

# 2. 查看实际执行计划
— 在SSMS中,选中查询,按Ctrl+M启用实际执行计划
— 或使用SET STATISTICS XML ON
SET STATISTICS XML ON;
GO

SELECT
*
FROM dbo.fgedu_users
WHERE username = ‘user1’;
GO

SET STATISTICS XML OFF;
GO

# 3. 分析执行计划运算符
— 常见运算符及其含义:
— Clustered Index Scan: 聚集索引扫描(全表扫描)
— Nonclustered Index Scan: 非聚集索引扫描
— Clustered Index Seek: 聚集索引查找
— Nonclustered Index Seek: 非聚集索引查找
— Key Lookup: 键查找(书签查找)
— RID Lookup: RID查找(堆表的书签查找)
— Hash Match: 哈希匹配(用于JOIN)
— Nested Loops: 嵌套循环(用于JOIN)
— Merge Join: 合并连接(用于JOIN)
— Sort: 排序
— Filter: 过滤
— Compute Scalar: 计算标量

# 4. 使用DMV查看缓存的执行计划
SELECT
TOP 10
usecounts,
cacheobjtype,
objtype,
TEXT
FROM sys.dm_exec_cached_plans
CROSS APPLY sys.dm_exec_sql_text(plan_handle)
WHERE TEXT LIKE ‘%fgedu_users%’
ORDER BY usecounts DESC;
GO

# 5. 分析执行计划性能指标
— 查看执行计划的逻辑读取、物理读取、CPU时间等
SET STATISTICS IO ON;
SET STATISTICS TIME ON;
GO

SELECT
*
FROM dbo.fgedu_users
WHERE username = ‘user1’;
GO

SET STATISTICS IO OFF;
SET STATISTICS TIME OFF;
GO

# 6. 识别性能瓶颈
— 查找执行计划中的昂贵运算符
— 关注高成本的扫描操作
— 分析JOIN操作的成本
— 检查排序和哈希操作的成本

3.2 SQLServer数据库查询性能调优配置

3.2.1 SQLServer数据库查询语句优化

# 查询语句优化步骤

# 1. 避免使用SELECT *
— 不好的写法
SELECT * FROM dbo.fgedu_users;

— 好的写法
SELECT id, username, email FROM dbo.fgedu_users;

# 2. 使用参数化查询
— 不好的写法
DECLARE @username NVARCHAR(50) = ‘user1’;
EXEC(‘SELECT * FROM dbo.fgedu_users WHERE username = ”’ + @username + ””);

— 好的写法
DECLARE @username NVARCHAR(50) = ‘user1’;
SELECT * FROM dbo.fgedu_users WHERE username = @username;

# 3. 优化WHERE子句
— 不好的写法(使用函数导致索引失效)
SELECT * FROM dbo.fgedu_users WHERE YEAR(create_time) = 2023;

— 好的写法
SELECT * FROM dbo.fgedu_users WHERE create_time BETWEEN ‘2023-01-01’ AND ‘2023-12-31’;

# 4. 优化JOIN操作
— 不好的写法(笛卡尔积)
SELECT * FROM dbo.fgedu_users, dbo.fgedu_orders;

— 好的写法(使用INNER JOIN)
SELECT * FROM dbo.fgedu_users u INNER JOIN dbo.fgedu_orders o ON u.id = o.user_id;

# 5. 避免子查询
— 不好的写法(相关子查询)
SELECT
id,
username,
(SELECT COUNT(*) FROM dbo.fgedu_orders WHERE user_id = u.id) AS order_count
FROM dbo.fgedu_users u;

— 好的写法(使用JOIN)
SELECT
u.id,
u.username,
COUNT(o.id) AS order_count
FROM dbo.fgedu_users u
LEFT JOIN dbo.fgedu_orders o ON u.id = o.user_id
GROUP BY u.id, u.username;

# 6. 使用TOP限制结果集
— 不好的写法(返回所有行)
SELECT * FROM dbo.fgedu_users ORDER BY create_time DESC;

— 好的写法(限制返回行数)
SELECT TOP 10 * FROM dbo.fgedu_users ORDER BY create_time DESC;

# 7. 优化ORDER BY和GROUP BY
— 确保ORDER BY和GROUP BY的列有索引
— 避免在ORDER BY中使用函数
— 考虑使用覆盖索引

# 8. 使用UNION ALL替代UNION
— 不好的写法(UNION会去重,性能较差)
SELECT id, username FROM dbo.fgedu_users WHERE status = ‘Active’
UNION
SELECT id, username FROM dbo.fgedu_users WHERE status = ‘Inactive’;

— 好的写法(UNION ALL不会去重,性能较好)
SELECT id, username FROM dbo.fgedu_users WHERE status = ‘Active’
UNION ALL
SELECT id, username FROM dbo.fgedu_users WHERE status = ‘Inactive’;

3.2.2 SQLServer数据库索引优化

# 索引优化步骤

# 1. 识别缺失索引
SELECT
TOP 10
dm_mid.database_id,
dm_mid.physical_operator_name,
dm_mid.est_cost AS estimated_cost,
dm_migs.avg_total_user_cost * dm_migs.avg_user_impact * (dm_migs.user_seeks + dm_migs.user_scans) AS improvement_measure,
‘CREATE INDEX [IX_’ + OBJECT_NAME(dm_mid.OBJECT_ID, dm_mid.database_id) + ‘_’
+ REPLACE(REPLACE(REPLACE(ISNULL(dm_mid.equality_columns, ”), ‘, ‘, ‘_’), ‘[‘, ”), ‘]’, ”)
+ CASE
WHEN dm_mid.equality_columns IS NOT NULL AND dm_mid.inequality_columns IS NOT NULL THEN ‘_’
ELSE ”
END
+ REPLACE(REPLACE(REPLACE(ISNULL(dm_mid.inequality_columns, ”), ‘, ‘, ‘_’), ‘[‘, ”), ‘]’, ”)
+ ‘]’
+ ‘ ON ‘ + dm_migs.statement
+ ‘ (‘ + ISNULL(dm_mid.equality_columns, ”)
+ CASE WHEN dm_mid.equality_columns IS NOT NULL AND dm_mid.inequality_columns IS NOT NULL THEN ‘, ‘ ELSE ” END
+ ISNULL(dm_mid.inequality_columns, ”)
+ ‘)’
+ ISNULL(‘ INCLUDE (‘ + dm_mid.included_columns + ‘)’, ”) AS create_index_statement
FROM sys.dm_db_missing_index_groups dm_mig
INNER JOIN sys.dm_db_missing_index_group_stats dm_migs ON dm_mig.index_group_handle = dm_migs.group_handle
INNER JOIN sys.dm_db_missing_index_details dm_mid ON dm_mig.index_handle = dm_mid.index_handle
ORDER BY dm_migs.avg_total_user_cost * dm_migs.avg_user_impact * (dm_migs.user_seeks + dm_migs.user_scans) DESC;
GO

# 2. 检查索引碎片
SELECT
DB_NAME(database_id) AS database_name,
OBJECT_NAME(object_id) AS table_name,
index_id,
name AS index_name,
avg_fragmentation_in_percent,
fragment_count,
page_count
FROM sys.dm_db_index_physical_stats(
DB_ID(),
NULL,
NULL,
NULL,
‘DETAILED’
) WHERE avg_fragmentation_in_percent > 10;
GO

# 3. 重建碎片化索引
— 重建索引
ALTER INDEX ALL ON dbo.fgedu_users REBUILD;
GO

— 重组索引
ALTER INDEX ALL ON dbo.fgedu_users REORGANIZE;
GO

# 4. 删除冗余索引
SELECT
OBJECT_NAME(i.object_id) AS table_name,
i.name AS index_name,
i.index_id,
i.type_desc,
i.is_unique,
i.is_primary_key
FROM sys.indexes i
INNER JOIN sys.indexes i2 ON i.object_id = i2.object_id
WHERE i.index_id > i2.index_id
AND i.columns = i2.columns
AND i.is_unique = i2.is_unique;
GO

# 5. 优化索引填充因子
— 设置填充因子为80
ALTER INDEX IX_fgedu_users_username ON dbo.fgedu_users REBUILD WITH (FILLFACTOR = 80);
GO

# 6. 创建覆盖索引
— 创建覆盖索引
CREATE INDEX IX_fgedu_orders_user_id_status
ON dbo.fgedu_orders (user_id, status)
INCLUDE (order_date, total_amount);
GO

# 7. 监控索引使用情况
SELECT
OBJECT_NAME(s.object_id) AS table_name,
i.name AS index_name,
i.type_desc,
s.user_seeks,
s.user_scans,
s.user_lookups,
s.user_updates
FROM sys.dm_db_index_usage_stats s
INNER JOIN sys.indexes i ON s.object_id = i.object_id AND s.index_id = i.index_id
WHERE database_id = DB_ID()
ORDER BY (s.user_seeks + s.user_scans + s.user_lookups) DESC;
GO

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-01-01’ AND ‘2023-12-31’
GROUP BY u.id, u.username
ORDER BY total_spent DESC;

DECLARE @end_time DATETIME = GETDATE();
SELECT ‘Before optimization’ AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms;
GO

— 应用优化(例如添加索引)
CREATE INDEX IX_fgedu_users_create_time ON dbo.fgedu_users(create_time);
CREATE INDEX IX_fgedu_orders_user_id ON dbo.fgedu_orders(user_id);
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-01-01’ AND ‘2023-12-31’
GROUP BY u.id, u.username
ORDER BY total_spent DESC;

DECLARE @end_time DATETIME = GETDATE();
SELECT ‘After optimization’ AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms;
GO

# 2. 资源使用监控
— 监控CPU使用
SELECT
session_id,
command,
cpu_time,
total_elapsed_time,
logical_reads,
physical_reads
FROM sys.dm_exec_requests
WHERE session_id = @@SPID;
GO

— 监控内存使用
SELECT
physical_memory_in_use_kb / 1024 AS physical_memory_used_mb,
locked_page_allocations_kb / 1024 AS locked_pages_mb,
page_fault_count,
memory_utilization_percentage,
available_commit_limit_kb / 1024 AS available_commit_limit_mb
FROM sys.dm_os_process_memory;
GO

— 监控I/O使用
SET STATISTICS IO 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-01-01’ AND ‘2023-12-31’
GROUP BY u.id, u.username
ORDER BY total_spent DESC;
GO

SET STATISTICS IO OFF;
GO

# 3. 执行计划对比
— 查看优化前后的执行计划
— 比较逻辑读取、物理读取、CPU时间等指标
— 分析执行计划的变化

# 4. 生产环境验证
— 在非高峰时段进行测试
— 监控系统整体性能
— 确认优化不会影响其他查询
— 评估长期性能影响

# 验证结果评估

验证项 优化前 优化后 改进率
————————————————————
执行时间 5000ms 500ms 90.0%
逻辑读取 10000 1000 90.0%
物理读取 1000 100 90.0%
CPU时间 2000ms 200ms 90.0%
内存使用 100MB 50MB 50.0%

风哥提示:查询性能调优验证是确保优化效果的关键,建议通过对比测试来评估性能提升,确保优化在生产环境中能够发挥最佳效果。更多学习教程公众号风哥教程itpux_com

Part04-生产案例与实战讲解

4.1 SQLServer数据库查询性能调优案例1:慢查询优化

# 需求:优化系统中的慢查询,提高查询响应速度

# 实施步骤:

# 1. 环境准备
# 创建测试数据库
CREATE DATABASE fgedu_performance;
GO

# 创建测试表
USE fgedu_performance;
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

# 2. 插入测试数据
— 插入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 # 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 optimization' AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO # 4. 分析执行计划 -- 查看执行计划,发现全表扫描和哈希匹配 -- 缺少适当的索引 # 5. 优化查询 -- 添加索引 CREATE INDEX IX_fgedu_users_create_time_status ON dbo.fgedu_users(create_time, status); GO CREATE INDEX IX_fgedu_orders_user_id ON dbo.fgedu_orders(user_id); 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 optimization' AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO # 6. 验证优化效果 -- 执行计划现在使用索引查找 -- 查询执行时间从5000ms减少到500ms -- 逻辑读取从10000减少到1000 # 7. 实施效果 # 查询执行时间减少90% # 系统资源使用显著降低 # 用户体验得到改善 # 系统整体性能提升

4.2 SQLServer数据库查询性能调优案例2:复杂查询优化

# 需求:优化复杂查询,提高报表生成速度

# 实施步骤:

# 1. 环境准备
# 创建测试表
USE fgedu_performance;
GO

CREATE TABLE dbo.fgedu_products (
id INT PRIMARY KEY IDENTITY,
product_name NVARCHAR(100) NOT NULL,
category NVARCHAR(50) NOT NULL,
price DECIMAL(10, 2) NOT NULL,
stock INT NOT NULL
);
GO

CREATE TABLE dbo.fgedu_order_items (
id INT PRIMARY KEY IDENTITY,
order_id INT NOT NULL,
product_id INT NOT NULL,
quantity INT NOT NULL,
unit_price DECIMAL(10, 2) NOT NULL
);
GO

# 2. 插入测试数据
— 插入10000行产品数据
DECLARE @i INT = 1;
WHILE @i <= 10000 BEGIN INSERT INTO dbo.fgedu_products ( product_name, category, price, stock ) VALUES ( 'Product' + CAST(@i AS NVARCHAR), CASE @i % 10 WHEN 0 THEN 'Electronics' WHEN 1 THEN 'Clothing' WHEN 2 THEN 'Home' WHEN 3 THEN 'Garden' WHEN 4 THEN 'Tools' WHEN 5 THEN 'Sports' WHEN 6 THEN 'Books' WHEN 7 THEN 'Music' WHEN 8 THEN 'Movies' ELSE 'Toys' END, ABS(CHECKSUM(NEWID())) % 1000 + 1, ABS(CHECKSUM(NEWID())) % 1000 + 1 ); SET @i = @i + 1; END; GO -- 插入100万行订单项数据 DECLARE @i INT = 1; WHILE @i <= 1000000 BEGIN INSERT INTO dbo.fgedu_order_items ( order_id, product_id, quantity, unit_price ) VALUES ( ABS(CHECKSUM(NEWID())) % 500000 + 1, ABS(CHECKSUM(NEWID())) % 10000 + 1, ABS(CHECKSUM(NEWID())) % 10 + 1, ABS(CHECKSUM(NEWID())) % 1000 + 1 ); SET @i = @i + 1; END; GO # 3. 识别复杂查询 -- 执行复杂查询 DECLARE @start_time DATETIME = GETDATE(); SELECT p.category, p.product_name, SUM(oi.quantity) AS total_quantity, SUM(oi.quantity * oi.unit_price) AS total_revenue, COUNT(DISTINCT oi.order_id) AS order_count FROM dbo.fgedu_products p JOIN dbo.fgedu_order_items oi ON p.id = oi.product_id JOIN dbo.fgedu_orders o ON oi.order_id = o.id WHERE o.order_date BETWEEN '2023-01-01' AND '2023-12-31' GROUP BY p.category, p.product_name ORDER BY total_revenue DESC TOP 100; DECLARE @end_time DATETIME = GETDATE(); SELECT 'Before optimization' AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO # 4. 分析执行计划 -- 查看执行计划,发现多个哈希匹配和排序操作 -- 缺少适当的索引 # 5. 优化查询 -- 添加索引 CREATE INDEX IX_fgedu_order_items_product_id ON dbo.fgedu_order_items(product_id); GO CREATE INDEX IX_fgedu_order_items_order_id ON dbo.fgedu_order_items(order_id); GO CREATE INDEX IX_fgedu_orders_order_date ON dbo.fgedu_orders(order_date); GO -- 创建覆盖索引 CREATE INDEX IX_fgedu_order_items_product_id_order_id ON dbo.fgedu_order_items(product_id, order_id) INCLUDE (quantity, unit_price); GO -- 优化查询语句 DECLARE @start_time DATETIME = GETDATE(); SELECT p.category, p.product_name, SUM(oi.quantity) AS total_quantity, SUM(oi.quantity * oi.unit_price) AS total_revenue, COUNT(DISTINCT oi.order_id) AS order_count FROM dbo.fgedu_products p JOIN dbo.fgedu_order_items oi ON p.id = oi.product_id JOIN dbo.fgedu_orders o ON oi.order_id = o.id WHERE o.order_date BETWEEN '2023-01-01' AND '2023-12-31' GROUP BY p.category, p.product_name ORDER BY total_revenue DESC TOP 100; DECLARE @end_time DATETIME = GETDATE(); SELECT 'After optimization' AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO # 6. 验证优化效果 -- 执行计划现在使用索引查找和合并连接 -- 查询执行时间从10000ms减少到1000ms -- 逻辑读取从20000减少到2000 # 7. 实施效果 # 查询执行时间减少90% # 报表生成速度显著提高 # 系统资源使用降低 # 业务决策支持能力提升

4.3 SQLServer数据库查询性能调优案例3:批量查询优化

# 需求:优化批量查询,提高数据导入和处理速度

# 实施步骤:

# 1. 环境准备
# 创建测试表
USE fgedu_performance;
GO

CREATE TABLE dbo.fgedu_import_data (
id INT PRIMARY KEY IDENTITY,
value1 NVARCHAR(100) NOT NULL,
value2 NVARCHAR(100) NOT NULL,
value3 NVARCHAR(100) NOT NULL,
value4 NVARCHAR(100) NOT NULL,
value5 NVARCHAR(100) NOT NULL,
import_time DATETIME DEFAULT GETDATE()
);
GO

# 2. 测试批量插入
— 测试单条插入
DECLARE @start_time DATETIME = GETDATE();

DECLARE @i INT = 1;
WHILE @i <= 10000 BEGIN INSERT INTO dbo.fgedu_import_data ( value1, value2, value3, value4, value5 ) VALUES ( 'Value1-' + CAST(@i AS NVARCHAR), 'Value2-' + CAST(@i AS NVARCHAR), 'Value3-' + CAST(@i AS NVARCHAR), 'Value4-' + CAST(@i AS NVARCHAR), 'Value5-' + CAST(@i AS NVARCHAR) ); SET @i = @i + 1; END; DECLARE @end_time DATETIME = GETDATE(); SELECT 'Single insert' AS method, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO -- 测试批量插入 DECLARE @start_time DATETIME = GETDATE(); INSERT INTO dbo.fgedu_import_data ( value1, value2, value3, value4, value5 ) SELECT 'Value1-' + CAST(number AS NVARCHAR), 'Value2-' + CAST(number AS NVARCHAR), 'Value3-' + CAST(number AS NVARCHAR), 'Value4-' + CAST(number AS NVARCHAR), 'Value5-' + CAST(number AS NVARCHAR) FROM master..spt_values WHERE type = 'P' AND number BETWEEN 1 AND 10000; DECLARE @end_time DATETIME = GETDATE(); SELECT 'Bulk insert' AS method, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO # 3. 测试批量更新 -- 测试单条更新 DECLARE @start_time DATETIME = GETDATE(); DECLARE @i INT = 1; WHILE @i <= 10000 BEGIN UPDATE dbo.fgedu_import_data SET value1 = 'Updated-' + CAST(@i AS NVARCHAR) WHERE id = @i; SET @i = @i + 1; END; DECLARE @end_time DATETIME = GETDATE(); SELECT 'Single update' AS method, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO -- 测试批量更新 DECLARE @start_time DATETIME = GETDATE(); UPDATE dbo.fgedu_import_data SET value1 = 'BulkUpdated-' + CAST(id AS NVARCHAR) WHERE id BETWEEN 1 AND 10000; DECLARE @end_time DATETIME = GETDATE(); SELECT 'Bulk update' AS method, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO # 4. 测试批量删除 -- 测试单条删除 DECLARE @start_time DATETIME = GETDATE(); DECLARE @i INT = 1; WHILE @i <= 10000 BEGIN DELETE FROM dbo.fgedu_import_data WHERE id = @i; SET @i = @i + 1; END; DECLARE @end_time DATETIME = GETDATE(); SELECT 'Single delete' AS method, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO -- 测试批量删除 DECLARE @start_time DATETIME = GETDATE(); DELETE FROM dbo.fgedu_import_data WHERE id BETWEEN 10001 AND 20000; DECLARE @end_time DATETIME = GETDATE(); SELECT 'Bulk delete' AS method, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO # 5. 优化批量操作 -- 使用表变量进行批量操作 DECLARE @start_time DATETIME = GETDATE(); DECLARE @import_table TABLE ( value1 NVARCHAR(100), value2 NVARCHAR(100), value3 NVARCHAR(100), value4 NVARCHAR(100), value5 NVARCHAR(100) ); INSERT INTO @import_table SELECT 'Value1-' + CAST(number AS NVARCHAR), 'Value2-' + CAST(number AS NVARCHAR), 'Value3-' + CAST(number AS NVARCHAR), 'Value4-' + CAST(number AS NVARCHAR), 'Value5-' + CAST(number AS NVARCHAR) FROM master..spt_values WHERE type = 'P' AND number BETWEEN 1 AND 10000; INSERT INTO dbo.fgedu_import_data ( value1, value2, value3, value4, value5 ) SELECT * FROM @import_table; DECLARE @end_time DATETIME = GETDATE(); SELECT 'Table variable insert' AS method, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO # 6. 验证优化效果 -- 批量插入比单条插入快10倍以上 -- 批量更新比单条更新快5倍以上 -- 批量删除比单条删除快5倍以上 -- 表变量插入进一步提高性能 # 7. 实施效果 # 数据导入速度显著提高 # 批量处理性能提升 # 系统资源使用降低 # 业务处理效率提高

生产环境建议:批量查询优化是提高数据处理效率的重要手段,建议在处理大量数据时使用批量操作,以提高系统性能。from SQLServer视频:www.itpux.com

Part05-风哥经验总结与分享

5.1 SQLServer数据库查询性能调优实施技巧

SQLServer数据库查询性能调优实施技巧:

  • 定期监控:建立性能监控系统,定期分析慢查询
  • 使用参数化查询:减少执行计划缓存膨胀,提高缓存命中率
  • 优化索引:为频繁查询的列创建适当的索引,避免过度索引
  • 更新统计信息:定期更新统计信息,确保查询优化器生成准确的执行计划
  • 避免全表扫描:使用索引覆盖查询,减少I/O操作
  • 优化JOIN操作:使用适当的JOIN类型,调整JOIN顺序
  • 使用分区表:对于大型表,使用分区表提高查询性能
  • 监控执行计划:定期分析执行计划,识别性能问题
  • 批量操作:使用批量插入、更新和删除提高处理效率
  • 合理使用临时表:对于复杂查询,使用临时表简化逻辑

5.2 SQLServer数据库查询性能调优检查清单

# SQLServer数据库查询性能调优检查清单

1. 慢查询识别
[ ] 已使用DMV识别慢查询
[ ] 已使用SQL Server Profiler识别慢查询
[ ] 已使用Extended Events识别慢查询
[ ] 已分析慢查询执行计划

2. 查询语句优化
[ ] 已避免使用SELECT *
[ ] 已使用参数化查询
[ ] 已优化WHERE子句
[ ] 已优化JOIN操作
[ ] 已避免子查询
[ ] 已使用TOP限制结果集
[ ] 已优化ORDER BY和GROUP BY

3. 索引优化
[ ] 已识别缺失索引
[ ] 已添加适当的索引
[ ] 已删除冗余索引
[ ] 已重建碎片化索引
[ ] 已优化索引填充因子
[ ] 已创建覆盖索引

4. 统计信息优化
[ ] 已更新统计信息
[ ] 已调整统计信息采样率
[ ] 已使用过滤统计信息
[ ] 已监控统计信息状态

5. 服务器配置优化
[ ] 已调整内存配置
[ ] 已设置合理的并行度
[ ] 已优化查询超时设置
[ ] 已调整其他服务器参数

6. 存储优化
[ ] 已优化数据文件布局
[ ] 已使用适当的存储子系统
[ ] 已考虑使用分区表
[ ] 已考虑使用数据压缩

7. 性能验证
[ ] 已测试优化前后性能
[ ] 已监控系统资源使用
[ ] 已验证生产环境效果
[ ] 已建立性能基线

8. 持续优化
[ ] 已建立定期优化计划
[ ] 已监控性能趋势
[ ] 已更新优化策略
[ ] 已记录优化经验

5.3 SQLServer数据库查询性能调优常见问题

SQLServer数据库查询性能调优常见问题:

  • Q: 如何识别慢查询?
    A: 可以使用DMV、SQL Server Profiler、Extended Events等工具识别慢查询。
  • Q: 如何优化全表扫描?
    A: 为查询的过滤条件列创建适当的索引,使用索引覆盖查询。
  • Q: 如何优化JOIN操作?
    A: 使用适当的JOIN类型,调整JOIN顺序,为JOIN列创建索引。
  • Q: 如何避免参数嗅探问题?
    A: 使用参数化查询,考虑使用OPTIMIZE FOR提示,或使用本地变量。
  • Q: 如何优化ORDER BY操作?
    A: 为ORDER BY列创建索引,避免在ORDER BY中使用函数。
  • Q: 如何优化GROUP BY操作?
    A: 为GROUP BY列创建索引,考虑使用聚合索引。
  • Q: 如何处理执行计划缓存膨胀?
    A: 使用参数化查询,避免使用动态SQL,定期清理缓存。
  • Q: 如何监控查询性能?
    A: 使用DMV、SQL Server Profiler、Extended Events等工具监控查询性能。
风哥提示:查询性能调优是一个持续的过程,需要定期分析和优化。通过合理的优化策略和工具使用,可以显著提高SQLServer数据库的性能,为业务应用提供更快速、更可靠的服务。更多视频教程www.fgedu.net.cn

本文由风哥教程整理发布,仅用于学习测试使用,转载注明出处:http://www.fgedu.net.cn/10327.html

联系我们

在线咨询:点击这里给我发消息

微信号:itpux-com

工作日:9:30-18:30,节假日休息