1. 首页 > SQLServer教程 > 正文

SQLServer教程FG090-SQLServer执行计划分析实战

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

Part01-基础概念与理论知识

1.1 SQLServer数据库执行计划概念

SQLServer执行计划是SQLServer查询优化器生成的一种指令集,用于指导SQLServer如何执行查询。执行计划包含了查询的执行步骤、使用的索引、连接方式、排序操作等信息,是SQLServer查询优化的核心。执行计划分析是识别查询性能问题、优化查询语句的重要手段,通过分析执行计划,可以了解查询的执行过程,识别性能瓶颈,从而采取相应的优化措施。更多视频教程www.fgedu.net.cn

SQLServer数据库执行计划的重要性:

  • 帮助理解查询执行过程
  • 识别性能瓶颈
  • 指导查询优化
  • 提高查询性能
  • 减少系统资源消耗

1.2 SQLServer数据库执行计划类型

# SQLServer数据库执行计划类型

1. 估计执行计划 (Estimated Execution Plan)
– 由查询优化器生成
– 基于统计信息估计
– 不实际执行查询
– 用于分析查询计划

2. 实际执行计划 (Actual Execution Plan)
– 实际执行查询后生成
– 包含实际执行统计信息
– 显示实际行数和执行时间
– 用于验证查询性能

3. 执行计划缓存 (Execution Plan Cache)
– 存储在内存中的执行计划
– 可被重复使用
– 减少编译时间
– 提高查询性能

# 执行计划运算符

1. 扫描运算符
– Clustered Index Scan:聚集索引扫描(全表扫描)
– Nonclustered Index Scan:非聚集索引扫描
– Table Scan:表扫描(堆表)

2. 查找运算符
– Clustered Index Seek:聚集索引查找
– Nonclustered Index Seek:非聚集索引查找
– Key Lookup:键查找(书签查找)
– RID Lookup:RID查找(堆表的书签查找)

3. 连接运算符
– Nested Loops:嵌套循环连接
– Hash Match:哈希匹配连接
– Merge Join:合并连接

4. 排序运算符
– Sort:排序
– Top:返回前N行

5. 聚合运算符
– Stream Aggregate:流式聚合
– Hash Match Aggregate:哈希聚合

6. 其他运算符
– Filter:过滤
– Compute Scalar:计算标量
– Concatenation:连接
– Bitmap:位图

# 执行计划成本

1. 估计成本
– 基于统计信息计算
– 用于查询优化器选择执行计划
– 单位为逻辑读

2. 实际成本
– 实际执行时的资源消耗
– 包括CPU时间、I/O时间等
– 用于性能分析

3. 成本组成
– I/O成本:数据读取成本
– CPU成本:计算成本
– 内存成本:内存使用成本

1.3 SQLServer数据库执行计划分析优势

SQLServer数据库执行计划分析优势:

  • 识别性能瓶颈:通过分析执行计划,识别查询中的性能瓶颈
  • 优化查询语句:根据执行计划,优化查询语句结构
  • 改进索引设计:识别缺失索引和索引使用情况
  • 提高查询性能:通过优化执行计划,提高查询性能
  • 减少资源消耗:降低CPU、内存和I/O使用
  • 指导系统调优:为系统配置和调优提供依据
风哥提示:执行计划分析是SQLServer性能优化的关键,通过分析执行计划,可以深入了解查询的执行过程,识别性能问题,从而采取相应的优化措施。学习交流加群风哥微信: itpux-com

Part02-生产环境规划与建议

2.1 SQLServer数据库执行计划分析规划

SQLServer数据库执行计划分析规划要点:

# 执行计划分析规划步骤

1. 需求分析
– 分析查询模式:点查询、范围查询、复杂查询等
– 识别高频查询:经常执行的查询语句
– 评估性能目标:响应时间、吞吐量等
– 分析系统资源:CPU、内存、I/O等

2. 分析策略
– 定期分析:定期分析执行计划
– 实时分析:实时监控执行计划
– 问题分析:针对性能问题进行分析
– 优化分析:优化前后对比分析

3. 工具选择
– SQL Server Management Studio (SSMS)
– SQL Server Profiler
– Extended Events
– Dynamic Management Views (DMVs)
– 第三方工具

4. 实施计划
– 优先级排序:按查询频率和性能影响排序
– 分析步骤:收集执行计划、分析性能瓶颈、提出优化建议
– 测试计划:验证优化效果
– 回滚策略:准备回滚方案

5. 监控策略
– 建立监控系统:监控执行计划变化
– 设置告警阈值:针对执行计划异常
– 定期报告:生成执行计划分析报告
– 性能基线:建立性能基准

# 规划参考

查询类型 分析频率 工具选择 优化频率 监控频率
————————————————————————
OLTP查询 每周 SSMS, DMVs 每周 每天
OLAP查询 每月 SSMS, Profiler 每月 每周
复杂查询 每次变更 SSMS, Extended Events 每次变更 每次变更
慢查询 实时 Profiler, DMVs 实时 实时

2.2 SQLServer数据库执行计划分析实施方案

SQLServer数据库执行计划分析实施方案:

# 执行计划分析实施方案

1. 收集执行计划
– 使用SSMS查看估计执行计划:Ctrl+L
– 使用SSMS查看实际执行计划:Ctrl+M
– 使用SET SHOWPLAN_XML ON命令
– 使用SET STATISTICS XML ON命令
– 使用SQL Server Profiler捕获执行计划
– 使用Extended Events捕获执行计划

2. 分析执行计划
– 查看执行计划运算符
– 分析执行计划成本
– 识别性能瓶颈
– 检查索引使用情况
– 分析连接类型和顺序
– 查看排序和聚合操作

3. 优化执行计划
– 重写查询语句
– 添加缺失索引
– 优化索引设计
– 更新统计信息
– 调整服务器配置
– 优化存储结构

4. 验证优化效果
– 测试查询性能
– 比较优化前后执行计划
– 监控系统资源使用
– 确认生产环境效果

5. 持续监控
– 监控执行计划变化
– 识别新的性能问题
– 定期分析执行计划
– 持续优化查询性能

# 实施步骤参考

步骤 任务 负责人 时间
————————————————————
1 需求分析 DBA 1周
2 工具准备 DBA 1天
3 执行计划收集 DBA 2天
4 执行计划分析 DBA 3天
5 优化方案设计 DBA 2天
6 测试环境实施 DBA 2天
7 性能测试 测试团队 2天
8 生产环境实施 DBA 1天
9 监控配置 运维团队 1天

2.3 SQLServer数据库执行计划分析最佳实践

SQLServer数据库执行计划分析最佳实践:

  • 定期分析执行计划:定期分析高频查询的执行计划
  • 使用实际执行计划:优先使用实际执行计划进行分析
  • 关注高成本运算符:重点分析成本高的运算符
  • 检查索引使用:确保查询使用了适当的索引
  • 分析连接类型:选择合适的连接类型
  • 监控执行计划变化:定期监控执行计划的变化
  • 优化统计信息:确保统计信息准确
  • 测试优化效果:在生产环境实施前进行充分测试
生产环境建议:执行计划分析实施方案应根据数据库的实际情况进行调整,建议在实施前进行充分测试,确保不会对系统性能造成负面影响。学习交流加群风哥QQ113257174

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

3.1 SQLServer数据库执行计划分析项目实施

3.1.1 SQLServer数据库执行计划分析环境准备

# 环境准备步骤

# 1. 检查SQLServer版本
SELECT @@VERSION;
GO

# 2. 创建测试数据库
CREATE DATABASE fgedu_plan;
GO

# 3. 创建测试表
USE fgedu_plan;
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. 创建索引 CREATE INDEX IX_fgedu_users_create_time ON dbo.fgedu_users(create_time); GO CREATE INDEX IX_fgedu_orders_user_id ON dbo.fgedu_orders(user_id); 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 'Initial performance' AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO

3.1.2 SQLServer数据库执行计划收集与分析

# 执行计划收集与分析步骤

# 1. 查看估计执行计划
— 使用SSMS查看估计执行计划(Ctrl+L)
— 或使用SET SHOWPLAN_XML ON
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

# 2. 查看实际执行计划
— 使用SSMS查看实际执行计划(Ctrl+M)
— 或使用SET STATISTICS XML ON
SET STATISTICS 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 STATISTICS XML OFF;
GO

# 3. 使用SQL Server Profiler捕获执行计划
— 启动SQL Server Profiler
— 创建跟踪,选择事件:Showplan XML
— 运行跟踪,执行查询
— 查看捕获的执行计划

# 4. 使用Extended Events捕获执行计划
— 创建Extended Events会话
CREATE EVENT SESSION [CaptureExecutionPlans] ON SERVER
ADD EVENT sqlserver.query_plan_xml(
ACTION(sqlserver.database_name,sqlserver.sql_text,sqlserver.username)
),
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/ExecutionPlans.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 [CaptureExecutionPlans] ON SERVER STATE = START;
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

— 查看捕获的执行计划
SELECT
event_data = CONVERT(xml, event_data)
FROM sys.fn_xe_file_target_read_file(‘/sqlserver/fgdata/ExecutionPlans*.xel’, NULL, NULL, NULL);
GO

# 5. 分析执行计划
— 查看执行计划运算符
— 分析执行计划成本
— 识别性能瓶颈
— 检查索引使用情况

# 6. 查看执行计划缓存
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

# 7. 查看执行计划详细信息
SELECT
TOP 10
query_plan,
TEXT
FROM sys.dm_exec_cached_plans
CROSS APPLY sys.dm_exec_sql_text(plan_handle)
CROSS APPLY sys.dm_exec_query_plan(plan_handle)
WHERE TEXT LIKE ‘%fgedu_users%’
ORDER BY usecounts DESC;
GO

3.2 SQLServer数据库执行计划分析配置

3.2.1 SQLServer数据库执行计划缓存配置

# 执行计划缓存配置步骤

# 1. 查看执行计划缓存设置
— 查看最大服务器内存
SELECT
name,
value,
value_in_use
FROM sys.configurations
WHERE name LIKE ‘%memory%’;
GO

— 查看执行计划缓存大小
SELECT
cache_size_mb = CONVERT(DECIMAL(12, 2), SUM(size_in_bytes) / 1024.0 / 1024.0),
cache_count = COUNT(*)
FROM sys.dm_exec_cached_plans;
GO

# 2. 配置执行计划缓存
— 设置最大服务器内存
EXEC sp_configure ‘max server memory (MB)’, 16384;
RECONFIGURE;
GO

— 设置最小服务器内存
EXEC sp_configure ‘min server memory (MB)’, 4096;
RECONFIGURE;
GO

# 3. 监控执行计划缓存
— 查看执行计划缓存使用情况
SELECT
objtype,
cache_size_mb = CONVERT(DECIMAL(12, 2), SUM(size_in_bytes) / 1024.0 / 1024.0),
cache_count = COUNT(*),
avg_usecounts = AVG(usecounts)
FROM sys.dm_exec_cached_plans
GROUP BY objtype
ORDER BY cache_size_mb DESC;
GO

— 查看执行计划缓存详细信息
SELECT
TOP 20
usecounts,
cacheobjtype,
objtype,
size_in_bytes / 1024.0 / 1024.0 AS size_in_mb,
TEXT
FROM sys.dm_exec_cached_plans
CROSS APPLY sys.dm_exec_sql_text(plan_handle)
ORDER BY size_in_bytes DESC;
GO

# 4. 清除执行计划缓存
— 清除所有执行计划缓存
DBCC FREEPROCCACHE;
GO

— 清除特定执行计划缓存
DECLARE @plan_handle VARBINARY(64);
SELECT @plan_handle = plan_handle
FROM sys.dm_exec_cached_plans
CROSS APPLY sys.dm_exec_sql_text(plan_handle)
WHERE TEXT LIKE ‘%fgedu_users%’;

DBCC FREEPROCCACHE(@plan_handle);
GO

# 5. 优化执行计划缓存
— 使用参数化查询
DECLARE @start_date DATETIME = ‘2023-06-01’;
DECLARE @end_date DATETIME = ‘2023-06-30’;
DECLARE @status NVARCHAR(20) = ‘Active’;

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 @start_date AND @end_date
AND u.status = @status
GROUP BY u.id, u.username
ORDER BY total_spent DESC
TOP 100;
GO

— 使用存储过程
CREATE PROCEDURE dbo.GetUserOrders
@start_date DATETIME,
@end_date DATETIME,
@status NVARCHAR(20)
AS
BEGIN
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 @start_date AND @end_date
AND u.status = @status
GROUP BY u.id, u.username
ORDER BY total_spent DESC
TOP 100;
END;
GO

— 执行存储过程
EXEC dbo.GetUserOrders ‘2023-06-01’, ‘2023-06-30’, ‘Active’;
GO

3.2.2 SQLServer数据库执行计划分析工具配置

# 执行计划分析工具配置步骤

# 1. SQL Server Management Studio (SSMS)配置
— 启用执行计划显示
— 工具 -> 选项 -> 查询执行 -> 高级 -> 启用执行计划

# 2. SQL Server Profiler配置
— 创建执行计划捕获模板
— 文件 -> 模板 -> 新建模板
— 选择事件:Showplan XML, Showplan Statistics Profile
— 设置筛选器:Duration > 1000ms

# 3. Extended Events配置
— 创建执行计划捕获会话
CREATE EVENT SESSION [ExecutionPlanAnalysis] ON SERVER
ADD EVENT sqlserver.query_plan_xml(
ACTION(sqlserver.database_name,sqlserver.sql_text,sqlserver.username)
),
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/ExecutionPlanAnalysis.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

# 4. Dynamic Management Views (DMVs)配置
— 启用高级DMVs
EXEC sp_configure ‘show advanced options’, 1;
RECONFIGURE;
GO

— 启用查询存储
ALTER DATABASE fgedu_plan SET QUERY_STORE = ON;
GO

— 配置查询存储
ALTER DATABASE fgedu_plan SET QUERY_STORE (
OPERATION_MODE = READ_WRITE,
CLEANUP_POLICY = (STALE_QUERY_THRESHOLD_DAYS = 30),
DATA_FLUSH_INTERVAL_SECONDS = 900,
MAX_STORAGE_SIZE_MB = 10240,
INTERVAL_LENGTH_MINUTES = 15,
QUERY_CAPTURE_MODE = AUTO,
MAX_PLANS_PER_QUERY = 200,
WAIT_STATS_CAPTURE_MODE = ON
);
GO

# 5. 第三方工具配置
— 根据实际使用的第三方工具进行配置
— 例如:SQL Sentry Plan Explorer, Redgate SQL Monitor等

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 optimization’ AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms;
GO

— 优化查询
— 添加索引
CREATE INDEX IX_fgedu_users_status_create_time ON dbo.fgedu_users(status, create_time);
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

# 2. 执行计划对比
— 查看优化前后的执行计划
— 比较执行计划运算符
— 比较执行计划成本
— 比较索引使用情况

# 3. 资源使用分析
— 监控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-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 STATISTICS IO OFF;
GO

— 监控CPU使用
SET STATISTICS TIME 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 STATISTICS TIME OFF;
GO

# 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. 环境准备
# 创建测试表
USE fgedu_plan;
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,
create_time DATETIME DEFAULT GETDATE()
);
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,
create_time DATETIME DEFAULT GETDATE()
);
GO

# 2. 插入测试数据
— 插入10000行产品数据
DECLARE @i INT = 1;
WHILE @i <= 10000 BEGIN INSERT INTO dbo.fgedu_products ( product_name, category, price, stock, create_time ) 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, DATEADD(DAY, @i % 365, '2023-01-01') ); 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, create_time ) VALUES ( ABS(CHECKSUM(NEWID())) % 500000 + 1, ABS(CHECKSUM(NEWID())) % 10000 + 1, ABS(CHECKSUM(NEWID())) % 10 + 1, ABS(CHECKSUM(NEWID())) % 1000 + 1, DATEADD(DAY, @i % 365, '2023-01-01') ); 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 FROM dbo.fgedu_products p JOIN dbo.fgedu_order_items oi ON p.id = oi.product_id WHERE p.create_time BETWEEN '2023-01-01' AND '2023-12-31' AND p.category = 'Electronics' GROUP BY p.category, p.product_name ORDER BY total_revenue DESC TOP 100; DECLARE @end_time DATETIME = GETDATE(); SELECT 'Slow query' AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO # 4. 分析执行计划 -- 查看执行计划,发现全表扫描和哈希匹配 -- 缺少适当的索引 # 5. 优化查询 -- 添加索引 CREATE INDEX IX_fgedu_products_category_create_time ON dbo.fgedu_products(category, create_time); GO CREATE INDEX IX_fgedu_order_items_product_id ON dbo.fgedu_order_items(product_id) INCLUDE (quantity, unit_price); GO # 6. 测试优化后性能 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 FROM dbo.fgedu_products p JOIN dbo.fgedu_order_items oi ON p.id = oi.product_id WHERE p.create_time BETWEEN '2023-01-01' AND '2023-12-31' AND p.category = 'Electronics' GROUP BY p.category, p.product_name ORDER BY total_revenue DESC TOP 100; DECLARE @end_time DATETIME = GETDATE(); SELECT 'Optimized query' AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO # 7. 验证优化效果 -- 执行计划现在使用索引查找 -- 查询执行时间从5000ms减少到500ms -- 逻辑读取从10000减少到1000 # 8. 实施效果 # 查询性能显著提高 # 系统资源使用降低 # 用户体验得到改善 # 系统整体性能提升

4.2 SQLServer数据库执行计划分析案例2:执行计划缓存分析

# 需求:分析执行计划缓存,提高缓存利用率

# 实施步骤:

# 1. 环境准备
# 查看执行计划缓存使用情况
SELECT
objtype,
cache_size_mb = CONVERT(DECIMAL(12, 2), SUM(size_in_bytes) / 1024.0 / 1024.0),
cache_count = COUNT(*),
avg_usecounts = AVG(usecounts)
FROM sys.dm_exec_cached_plans
GROUP BY objtype
ORDER BY cache_size_mb DESC;
GO

# 2. 识别缓存膨胀
— 查看缓存中的SQL语句
SELECT
TOP 20
usecounts,
cacheobjtype,
objtype,
size_in_bytes / 1024.0 / 1024.0 AS size_in_mb,
TEXT
FROM sys.dm_exec_cached_plans
CROSS APPLY sys.dm_exec_sql_text(plan_handle)
ORDER BY size_in_bytes DESC;
GO

# 3. 分析参数化查询
— 执行非参数化查询
DECLARE @category NVARCHAR(50) = ‘Electronics’;
EXEC(‘SELECT * FROM dbo.fgedu_products WHERE category = ”’ + @category + ””);
GO

— 执行参数化查询
DECLARE @category NVARCHAR(50) = ‘Electronics’;
SELECT * FROM dbo.fgedu_products WHERE category = @category;
GO

# 4. 查看缓存中的执行计划
SELECT
usecounts,
cacheobjtype,
objtype,
TEXT
FROM sys.dm_exec_cached_plans
CROSS APPLY sys.dm_exec_sql_text(plan_handle)
WHERE TEXT LIKE ‘%fgedu_products%’ AND TEXT LIKE ‘%category%’;
GO

# 5. 优化执行计划缓存
— 使用存储过程
CREATE PROCEDURE dbo.GetProductsByCategory
@category NVARCHAR(50)
AS
BEGIN
SELECT * FROM dbo.fgedu_products WHERE category = @category;
END;
GO

— 执行存储过程
EXEC dbo.GetProductsByCategory ‘Electronics’;
GO

— 再次执行存储过程
EXEC dbo.GetProductsByCategory ‘Clothing’;
GO

# 6. 查看存储过程的执行计划缓存
SELECT
usecounts,
cacheobjtype,
objtype,
TEXT
FROM sys.dm_exec_cached_plans
CROSS APPLY sys.dm_exec_sql_text(plan_handle)
WHERE TEXT LIKE ‘%GetProductsByCategory%’;
GO

# 7. 监控执行计划缓存使用情况
— 定期监控执行计划缓存
SELECT
objtype,
cache_size_mb = CONVERT(DECIMAL(12, 2), SUM(size_in_bytes) / 1024.0 / 1024.0),
cache_count = COUNT(*),
avg_usecounts = AVG(usecounts)
FROM sys.dm_exec_cached_plans
GROUP BY objtype
ORDER BY cache_size_mb DESC;
GO

# 8. 验证优化效果
— 执行计划缓存利用率提高
— 缓存中的执行计划数量减少
— 查询性能提高

# 9. 实施效果
# 执行计划缓存利用率提高
# 系统资源使用降低
# 查询性能提升
# 系统整体性能改善

4.3 SQLServer数据库执行计划分析案例3:参数嗅探问题分析

# 需求:分析参数嗅探问题,提高查询性能

# 实施步骤:

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

CREATE TABLE dbo.fgedu_sales (
id INT PRIMARY KEY IDENTITY,
product_id INT NOT NULL,
customer_id INT NOT NULL,
sale_date DATETIME DEFAULT GETDATE(),
amount DECIMAL(10, 2) NOT NULL,
region NVARCHAR(50) NOT NULL
);
GO

# 2. 插入测试数据
— 插入大部分数据为’North’地区
DECLARE @i INT = 1;
WHILE @i <= 990000 BEGIN INSERT INTO dbo.fgedu_sales ( product_id, customer_id, sale_date, amount, region ) VALUES ( ABS(CHECKSUM(NEWID())) % 10000 + 1, ABS(CHECKSUM(NEWID())) % 100000 + 1, DATEADD(DAY, @i % 365, '2023-01-01'), ABS(CHECKSUM(NEWID())) % 10000 + 1, 'North' ); SET @i = @i + 1; END; GO -- 插入少量数据为'South'地区 DECLARE @i INT = 1; WHILE @i <= 10000 BEGIN INSERT INTO dbo.fgedu_sales ( product_id, customer_id, sale_date, amount, region ) VALUES ( ABS(CHECKSUM(NEWID())) % 10000 + 1, ABS(CHECKSUM(NEWID())) % 100000 + 1, DATEADD(DAY, @i % 365, '2023-01-01'), ABS(CHECKSUM(NEWID())) % 10000 + 1, 'South' ); SET @i = @i + 1; END; GO # 3. 创建索引 CREATE INDEX IX_fgedu_sales_region ON dbo.fgedu_sales(region); GO # 4. 创建存储过程 CREATE PROCEDURE dbo.GetSalesByRegion @region NVARCHAR(50) AS BEGIN SELECT region, COUNT(*) AS sale_count, SUM(amount) AS total_amount FROM dbo.fgedu_sales WHERE region = @region GROUP BY region; END; GO # 5. 测试参数嗅探问题 -- 第一次执行,使用'North'地区(数据量多) DECLARE @start_time DATETIME = GETDATE(); EXEC dbo.GetSalesByRegion 'North'; DECLARE @end_time DATETIME = GETDATE(); SELECT 'North region' AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO -- 第二次执行,使用'South'地区(数据量少) DECLARE @start_time DATETIME = GETDATE(); EXEC dbo.GetSalesByRegion 'South'; DECLARE @end_time DATETIME = GETDATE(); SELECT 'South region' AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO # 6. 分析执行计划 -- 查看执行计划,发现使用了相同的执行计划 -- 对于'South'地区,应该使用索引查找,但可能使用了索引扫描 # 7. 解决参数嗅探问题 -- 方法1:使用OPTION(RECOMPILE) ALTER PROCEDURE dbo.GetSalesByRegion @region NVARCHAR(50) AS BEGIN SELECT region, COUNT(*) AS sale_count, SUM(amount) AS total_amount FROM dbo.fgedu_sales WHERE region = @region GROUP BY region OPTION(RECOMPILE); END; GO -- 方法2:使用本地变量 ALTER PROCEDURE dbo.GetSalesByRegion @region NVARCHAR(50) AS BEGIN DECLARE @local_region NVARCHAR(50) = @region; SELECT region, COUNT(*) AS sale_count, SUM(amount) AS total_amount FROM dbo.fgedu_sales WHERE region = @local_region GROUP BY region; END; GO -- 方法3:使用OPTIMIZE FOR ALTER PROCEDURE dbo.GetSalesByRegion @region NVARCHAR(50) AS BEGIN SELECT region, COUNT(*) AS sale_count, SUM(amount) AS total_amount FROM dbo.fgedu_sales WHERE region = @region GROUP BY region OPTION(OPTIMIZE FOR (@region = 'South')); END; GO # 8. 测试优化效果 -- 测试'North'地区 DECLARE @start_time DATETIME = GETDATE(); EXEC dbo.GetSalesByRegion 'North'; DECLARE @end_time DATETIME = GETDATE(); SELECT 'North region' AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO -- 测试'South'地区 DECLARE @start_time DATETIME = GETDATE(); EXEC dbo.GetSalesByRegion 'South'; DECLARE @end_time DATETIME = GETDATE(); SELECT 'South region' AS status, DATEDIFF(MS, @start_time, @end_time) AS execution_time_ms; GO # 9. 验证优化效果 -- 两个地区的查询性能都得到改善 -- 执行计划根据参数值动态生成 -- 系统资源使用降低 # 10. 实施效果 # 参数嗅探问题解决 # 查询性能显著提高 # 系统资源使用降低 # 系统整体性能提升

生产环境建议:参数嗅探是SQLServer中常见的性能问题,建议使用适当的方法解决,如OPTION(RECOMPILE)、本地变量或OPTIMIZE FOR提示,以确保查询性能稳定。from SQLServer视频:www.itpux.com

Part05-风哥经验总结与分享

5.1 SQLServer数据库执行计划分析实施技巧

SQLServer数据库执行计划分析实施技巧:

  • 定期分析执行计划:定期分析高频查询的执行计划,识别性能问题
  • 使用实际执行计划:优先使用实际执行计划进行分析,获得准确的执行统计信息
  • 关注高成本运算符:重点分析成本高的运算符,如全表扫描、哈希匹配等
  • 检查索引使用:确保查询使用了适当的索引,识别缺失索引
  • 分析连接类型:根据数据分布选择合适的连接类型,如嵌套循环、哈希匹配或合并连接
  • 监控执行计划缓存:定期监控执行计划缓存,识别缓存膨胀和参数嗅探问题
  • 优化统计信息:确保统计信息准确,避免执行计划选择错误
  • 使用参数化查询:减少执行计划缓存膨胀,提高缓存利用率
  • 测试优化效果:在生产环境实施前,进行充分的性能测试
  • 持续监控:定期监控执行计划变化,及时发现和解决性能问题

5.2 SQLServer数据库执行计划分析检查清单

# SQLServer数据库执行计划分析检查清单

1. 执行计划收集
[ ] 已收集估计执行计划
[ ] 已收集实际执行计划
[ ] 已使用SQL Server Profiler捕获执行计划
[ ] 已使用Extended Events捕获执行计划
[ ] 已查看执行计划缓存

2. 执行计划分析
[ ] 已分析执行计划运算符
[ ] 已分析执行计划成本
[ ] 已识别性能瓶颈
[ ] 已检查索引使用情况
[ ] 已分析连接类型和顺序

3. 执行计划优化
[ ] 已重写查询语句
[ ] 已添加缺失索引
[ ] 已优化索引设计
[ ] 已更新统计信息
[ ] 已调整服务器配置

4. 执行计划缓存管理
[ ] 已监控执行计划缓存使用情况
[ ] 已识别缓存膨胀
[ ] 已解决参数嗅探问题
[ ] 已优化执行计划缓存利用率
[ ] 已定期清理执行计划缓存

5. 性能验证
[ ] 已测试查询性能
[ ] 已比较优化前后执行计划
[ ] 已监控系统资源使用
[ ] 已验证生产环境效果
[ ] 已建立性能基线

6. 持续监控
[ ] 已建立执行计划监控系统
[ ] 已设置执行计划异常告警
[ ] 已定期分析执行计划
[ ] 已记录执行计划分析结果
[ ] 已更新执行计划优化策略

5.3 SQLServer数据库执行计划分析常见问题

SQLServer数据库执行计划分析常见问题:

  • Q: 如何查看执行计划?
    A: 使用SSMS的Ctrl+L查看估计执行计划,Ctrl+M查看实际执行计划,或使用SET SHOWPLAN_XML ON命令。
  • Q: 什么是执行计划缓存?
    A: 执行计划缓存是SQLServer存储在内存中的执行计划,可被重复使用,减少编译时间。
  • Q: 如何识别性能瓶颈?
    A: 通过分析执行计划中的高成本运算符,如全表扫描、哈希匹配等。
  • Q: 什么是参数嗅探?
    A: 参数嗅探是SQLServer使用第一次执行时的参数值生成执行计划,可能导致后续使用不同参数值时性能下降的问题。
  • Q: 如何解决参数嗅探问题?
    A: 使用OPTION(RECOMPILE)、本地变量或OPTIMIZE FOR提示。
  • Q: 如何优化执行计划缓存?
    A: 使用参数化查询、存储过程,减少执行计划缓存膨胀。
  • Q: 执行计划中的成本是什么意思?
    A: 执行计划中的成本是查询优化器基于统计信息估计的资源消耗,单位为逻辑读。
  • Q: 如何识别缺失索引?
    A: 通过执行计划中的索引建议,或使用sys.dm_db_missing_index_groups等DMV。
风哥提示:执行计划分析是SQLServer性能优化的核心技能,通过深入分析执行计划,可以识别性能瓶颈,优化查询语句,提高系统性能。建议DBA人员掌握执行计划分析技巧,定期分析和优化执行计划,确保系统的高效运行。更多视频教程www.fgedu.net.cn

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

联系我们

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

微信号:itpux-com

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