第七期:查询优化器与执行计划 —— 如何读懂与干预
Clyde Jin
04-25
DBA
188

第七期:查询优化器与执行计划 —— 如何读懂与干预

1. 查询优化器的工作流程

SQL Server 执行一条查询的完整路径:


T-SQL 语句

    ↓

【解析】语法检查 → 生成解析树

    ↓

【绑定】代数化(Algebrizer)→ 绑定到对象(表、视图、列),生成逻辑树(查询树)

    ↓

【优化】Query Optimizer → 基于代价生成多个候选计划 → 选择代价最低的

    ↓

【生成】执行计划 → 存入计划缓存

    ↓

【执行】Query Executor + Storage Engine → 返回结果

优化器的核心任务:在有限时间内找到“足够好”的执行计划(不是绝对最优,否则优化本身成本太高)。

三个阶段

| 阶段 | 策略 | 时间 | 搜索范围 |

|——|——|——|———-|

| 阶段0 | 事务处理(Trivial Plan) | 极快 | 只生成最简单的计划(如行数=1时直接扫描) |

| 阶段1 | 探索阶段(Exploration) | 快 | 搜索部分有希望的变换规则 |

| 阶段2 | 完全优化(Full Optimization) | 慢 | 搜索全部变换规则(并行计划也在此生成) |

现象解释

  • 为什么简单查询几乎瞬间返回执行计划?因为命中了阶段0,直接生成Trivial Plan。

  • 为什么复杂查询第一次编译时间长?因为优化器需要搜索多个候选计划(阶段2)。

2. 执行计划基础:读懂图形化计划

三种获取执行计划的方式

| 方式 | 命令 | 特点 |

|——|——|——|

| 估计执行计划 | SET SHOWPLAN_XML ON | 不执行查询,基于统计信息估算 |

| 实际执行计划 | SET STATISTICS XML ON | 执行查询,包含实际行数、运行时信息 |

| 实时执行计划 | sp_WhoIsActive 或 DMV | 查看正在执行的计划的实时进度(2016+) |

核心运算符(从数据流向角度理解)

| 运算符 | 作用 | 图标特征 |

|——–|——|———-|

| Clustered Index Seek | 在聚集索引中精确查找 | 黄色箭头+放大镜 |

| Clustered Index Scan | 扫描整个聚集索引(表扫描) | 黄色箭头+表格 |

| Index Seek | 在非聚集索引中精确查找 | 绿色箭头+放大镜 |

| Index Scan | 扫描整个非聚集索引 | 绿色箭头+表格 |

| Key Lookup(Bookmark Lookup) | 从非聚集索引回到聚集索引/堆取行 | 小书签图标 |

| Nested Loops | 循环嵌套连接(适用于小表驱动大表) | 两个圆套在一起 |

| Hash Match | 哈希连接(适用于大表无索引) | 两个圆相交 |

| Merge Join | 合并连接(适用于两个有序输入) | 齿轮状 |

| Sort | 显式排序 | 带A-Z的箭头 |

| Filter | 筛选行 | 漏斗 |

| Compute Scalar | 计算标量表达式 | 计算器 |

读取顺序从右到左、从下到上(执行顺序:子节点先执行,结果返回父节点)。

关键属性

  • 估计行数:优化器根据统计信息预估的行数

  • 实际行数:实际执行返回的行数(实际计划中才有)

  • 估计I/O/CPU代价:相对单位,用于比较计划

  • 估计子树代价:该节点及以下的总代价(优化器选计划的核心依据)

现象解释

  • 为什么估计行数和实际行数相差很大?统计信息过期或采样不准,优化器基于错误数据选了错误计划。

3. 统计信息:优化器的“眼睛”

统计信息的内容

  • 密度向量(Density):列上重复值的分布(=1/唯一值数)

  • 直方图(Histogram):最多200步,记录列值范围和行数分布

  • 字符串摘要(String Summary):用于LIKE查询的估算

统计信息自动维护

  • 自动创建(Auto Create):当查询引用无统计信息的列时

  • 自动更新(Auto Update):当行数变化超过阈值时

  • 行数 < 500:变化超过500行触发

  • 行数 > 500:变化超过 500 + 20% 行数触发

手动管理统计信息


-- 查看统计信息

DBCC SHOW_STATISTICS ('Orders', 'IX_Orders_OrderDate');

-- 更新统计信息(全表扫描)

UPDATE STATISTICS Orders IX_Orders_OrderDate WITH FULLSCAN;

-- 更新表上所有统计信息

UPDATE STATISTICS Orders WITH FULLSCAN;

-- 更新数据库所有统计信息

EXEC sp_updatestats;

统计信息问题现象

| 现象 | 统计信息问题 |

|——|————–|

| 实际行数远小于估计行数 | 统计信息过高估计 |

| 实际行数远大于估计行数 | 统计信息过低估计 |

| 参数嗅探导致错误计划 | 统计信息准确但优化器基于特定参数值做了错误决策 |

| 查询突然变慢,重建统计后恢复 | 统计信息过期 |

4. 计划缓存与重用

计划缓存位置:内存中(属于缓冲池之外的计划缓存区域)

计划缓存的优势

  • 节省编译时间(复杂查询可节省70%~90%编译开销)

  • 减少CPU使用

计划不能被重用的情况

  • 查询未被参数化(Ad-hoc查询使用文字常量)

  • 参数值差异大导致嗅探问题(强制重新编译)

  • 表结构变化(索引增删)

  • 统计信息更新

  • OPTION (RECOMPILE) 显式指定

管理计划缓存


-- 查看缓存计划

SELECT usecounts, cacheobjtype, objtype, size_in_bytes, sql_handle, plan_handle

FROM sys.dm_exec_cached_plans;

-- 清除所有缓存计划(谨慎)

DBCC FREEPROCCACHE;

-- 清除特定计划

DBCC FREEPROCCACHE (plan_handle);

-- 清除特定数据库的计划

DBCC FLUSHPROCINDB (db_id);

参数嗅探(Parameter Sniffing)

  • 定义:优化器在第一次编译时使用传入的参数值生成计划,后续复用时即使参数不同仍用同一计划。

  • 示例


-- 第一次执行:@Status = 'Active'(有10000行,优化器选表扫描)

-- 第二次执行:@Status = 'Archived'(只有10行,但沿用扫描计划 → 慢!)

CREATE PROC GetOrders @Status VARCHAR(20) AS

SELECT * FROM Orders WHERE Status = @Status;
  • 解决OPTION (RECOMPILE)OPTION (OPTIMIZE FOR UNKNOWN)、使用本地变量或OPTION (OPTIMIZE FOR (@Status='Active'))

5. 常见执行计划问题与优化

| 问题 | 执行计划特征 | 根本原因 | 解决方案 |

|——|————–|———-|———-|

| 全表扫描(死)| Clustered Index Scan 代价极高 | 无合适索引,或查询不SARG | 添加索引,重写查询 |

| 书签查找过多 | Key Lookup 占总代价80%+ | 非聚集索引未覆盖查询列 | 添加INCLUDE列,或使用覆盖索引 |

| 隐士转换 | Scan + CONVERT_IMPLICIT | 参数类型与列类型不匹配 | 统一参数类型(如传入’123’而非123) |

| 排序代价高 | Sort 占大量代价 | 无索引支持ORDER BY/GROUP BY | 在排序列上建索引 |

| 连接顺序错 | Hash Join 驱动表选错 | 统计信息不准 | 更新统计信息,或使用OPTION(FORCE ORDER) |

| 并行计划过多 | 多个并行运算符 | 查询复杂但数据量小 | 降低MAXDOP,或加OPTION(MAXDOP 1) |

SARGable查询原则(Search ARGument able):


-- 坏(非SARG):函数包裹列

WHERE YEAR(OrderDate) = 2024

-- 好(SARGable):列单独出现

WHERE OrderDate >= '2024-01-01' AND OrderDate < '2025-01-01'

-- 坏(非SARG):列在表达式中

WHERE Price * 1.1 > 100

-- 好(SARGable)

WHERE Price > 100 / 1.1

6. 干预优化器的方法

| 方法 | 语法 | 适用场景 |

|——|——|———-|

| 查询提示 | WITH (INDEX=IX_Name) | 强制使用特定索引 |

| 连接提示 | OPTION (HASH JOIN, MERGE JOIN) | 强制连接算法 |

| 强制顺序 | OPTION (FORCE ORDER) | 按FROM顺序执行连接 |

| 重编译 | OPTION (RECOMPILE) | 防止参数嗅探,或每次参数差异大 |

| 优化未知 | OPTION (OPTIMIZE FOR UNKNOWN) | 参数嗅探,使用平均值估算 |

| 指定值 | OPTION (OPTIMIZE FOR (@Status='Active')) | 让优化器基于特定值优化 |

| MAXDOP | OPTION (MAXDOP 2) | 限制并行度 |

| 表提示 | WITH (NOLOCK, READPAST) | 控制锁行为 |

提示使用原则

  • 先验证问题(确认优化器选错了计划)

  • 最小化干预(优先改查询/索引/统计信息)

  • 测试所有场景(防止一个查询改好,其他查询变差)

  • 代码注释原因(为什么强制这个提示)

7. 执行计划分析实战步骤


1. 获取实际执行计划(SET STATISTICS XML ON)

2. 找出代价最高的运算符(通常占80%+代价)

3. 检查估计行数 vs 实际行数差异

&#x20;  - 差异大 → 更新统计信息

&#x20;  - 差异小但计划仍差 → 索引或查询结构问题

4. 检查是否有表扫描/索引扫描(如果是大表且非必要)

5. 检查是否有大量书签查找(考虑覆盖索引)

6. 检查连接算法(循环嵌套适用于小表驱动大表)

7. 检查排序/Sort开销(考虑索引支持)

8. 检查隐式转换(CONVERT_IMPLICIT)

9. 设计改进方案(索引/查询/统计信息)

10. 验证改进效果(对比代价和解锁时间)

第七期小结

查询优化器基于代价在有限时间内选择“足够好”的执行计划,其决策质量高度依赖统计信息的准确性。读懂执行计划要学会从右到左、从下到上,找出高代价运算符,并判断根因(索引缺失/统计信息过期/参数嗅探)。干预优化器应遵循“先优化结构,后使用提示”的原则。核心目标:消除扫描、减少书签查找、确保连接顺序合理。

下期预告:存储引擎深度(四)—— 事务与并发控制的内部实现,深入理解行版本、日志序列号(LSN)和恢复过程。

Star
Donate
第六期:并发控制(下)—— 死锁检测、分析与消除
Previous
第八期:存储引擎深度(四)—— 事务与并发控制的内部实现
Next

Leave a comment

Registration is not required

Clyde Jin
303 Articles
0 Comments
0 Like
Recent Posts

HiddenMerit Daily · Issue 60

📊 HiddenMerit Daily · Issue 60 Focus on Database Frontiers, Practical Insights for DBAs July 22, 2026 | 5 Selected Global Breaking News 01|Oracle Releases Largest Quarterly Patch in History: 1,449 Patches Fix 1,235 CVEs, 261 Critical On July 21, Oracle released its July 2026 Critical Patch Update (CPU), setting a record for the largest single patch release in the company’s history. This CPU contains 1,449 security patches fixing 1,235 independent CVEs across 32 Oracle product families, of which 261 patches are rated Critical. Patch Distribution by Product Family: Product Family Patches Remotely Exploitable Without Authentication Oracle E‑Business Suite 410 45 Oracle Fusion Middleware 355 219 Oracle Communications 168 122 Oracle MySQL 54 9 Oracle Database Server 15 6 Context for This Patch: Oracle had already issued an urgent “Prepare Now” warning a week earlier, emphasising that AI is fundamentally lowering the barrier to discovering and exploiting vulnerabilities – frontier AI models can analyse software changes, reverse‑engineer security patches, and develop attack paths at unprecedented speed. Oracle has collaborated with state‑of‑the‑art models from Anthropic and OpenAI to proactively identify and fix potential security vulnerabilities. Oracle strongly recommends that customers immediately test and deploy this update in their monthly patch cycles. […]

HiddenMerit Daily · Issue 59

📊 HiddenMerit Daily · Issue 59 Focus on Database Frontiers, Practical Insights for DBAs July 21, 2026 | 5 Selected Global Breaking News 01|Oracle Issues Urgent Warning: July 21 Release Update to Fix Large Number of High‑Risk Vulnerabilities, Immediate Deployment Recommended On July 13, Oracle issued an urgent security warning, strongly recommending that all customers running supported Oracle Database versions (including Oracle Database 19c and Oracle AI Database 26ai) immediately test and deploy the Release Update (RU) after its release on July 21. Background: New frontier AI models are significantly lowering the barrier to discovering and exploiting software vulnerabilities – these models can identify weaknesses, analyse software changes, reverse‑engineer security patches, and develop potential attack paths at unprecedented speed and scale. AI models are also becoming increasingly adept at combining multiple weaknesses across the application and data stack into complex attacks, even when individual weaknesses do not themselves pose a serious risk. As a result, protecting systems solely at the network or application layer is no longer sufficient; enterprises must protect the entire technology stack. Fixes Included in This RU: Oracle has collaborated with state‑of‑the‑art models from Anthropic and OpenAI to proactively identify and fix potential security vulnerabilities. The upcoming […]

HiddenMerit Daily · Issue 58

📊 HiddenMerit Daily · Issue 58 Focus on Database Frontiers, Practical Insights for DBAs July 20, 2026 | 5 Selected Global Breaking News 01|CAICT: Domestic Databases Enter Core System “Deep Water,” AI‑Native Leads New Industry Landscape On July 9, at the 2026 Trustworthy Database Development Conference, CAICT released the “Database Development Research Report (2026).” The report notes that domestic databases have basically completed peripheral system replacement and have officially entered the critical business system breakthrough phase. Key Data: The global database market reached $131.6 billion in 2025 (approximately RMB 894.09 billion). The Chinese database market reached $9.49 billion in 2025 (approximately RMB 64.48 billion), and is expected to reach RMB 97.974 billion by 2028, with a CAGR of 13.06%. The number of domestic database vendors has shrunk from a peak of 167 to 94, with a clear head‑concentration effect and an intensifying “Matthew effect.” AI‑Native Becomes the Main Theme: The report points out that database technology is accelerating its evolution toward the AI‑native direction, and the global database industry is entering a new phase of landscape restructuring. The role of databases is upgrading from “underlying support systems” to “core engines enabling intelligent decision‑making and business innovation.” AI agents are becoming […]

HiddenMerit Daily · Issue 56

📊 HiddenMerit Daily · Issue 56 Focus on Database Frontiers, Practical Insights for DBAs July 6, 2026 | 5 Selected Global Breaking News 01|Kingware Releases Manufacturing Scenario Database Evolution White Paper: SQL Server Replacement Enters “Deep Water” On July 5, CETC Kingware published a technical article titled “Database Evolution in Manufacturing Scenarios: How Kingware Replaces SQL Server,” pointing out that the data surge on industrial shop floors has exceeded the processing capacity of single‑node systems. Traditional database architectures that rely on vertical scaling are facing unprecedented performance challenges. Over the next 1‑3 years, manufacturing enterprises will no longer face only the “choice of replacement,” but must answer the strategic question: “How do we build an autonomous data foundation in the context of de‑IOE?” Three Paradigm Shifts: Hybrid Workloads Become the Norm: The IT architecture of modern factories is shifting from separated OLTP and OLAP to HTAP mode. The same data system must simultaneously handle tens of thousands of device instruction writes per second and minute‑level production report analysis. Distributed Architecture Becomes a Hard Requirement: When a single table exceeds 100 million rows with daily increments exceeding 1 million rows, the index maintenance cost of traditional single‑node databases rises exponentially. Autonomous […]
生成中...
扫描二维码
扫描二维码