MS SQL Server中复杂SQL查询作为视图执行时性能差异大的原因
是否存在通用解释,说明为何封装在View中的SQL查询,执行性能远逊于作为普通查询执行的情况?
事情源于一个包含复杂查询的View性能表现极差,我随即展开原因分析。我进行了两组对比测试:
- 测试1:创建View并基于其执行SELECT-WHERE语句,耗时超20分钟;
- 测试2:将View的查询内容嵌入FROM子句执行相同的SELECT-WHERE语句,耗时不到1分钟。
测试代码如下:
测试1:
CREATE VIEW V AS SELECT <DEF> WHERE <EXPR> GO SELECT * FROM V WHERE <EXPR2> GO
测试2:
SELECT V.* FROM ( SELECT <DEF> WHERE <EXPR> ) V WHERE <EXPR2>
这种性能差异通常由以下几个核心原因导致:
查询计划缓存与参数嗅探问题
数据库创建视图后,可能会缓存一个通用执行计划。当你基于视图执行带<EXPR2>过滤条件的查询时,这个缓存计划可能无法适配当前过滤逻辑,导致执行路径低效。而子查询形式的语句会针对当前过滤条件重新生成最优计划,能更好地利用索引、提前过滤数据。视图展开限制
部分数据库的查询优化器无法完全将视图逻辑与外层查询的过滤条件合并(即无法"展开"视图并全局优化)。这会导致视图先执行<EXPR>过滤生成全量结果,再在外层应用<EXPR2>过滤,相当于两次扫描且中间结果集极大。子查询形式下,优化器可以合并<EXPR>和<EXPR2>的条件,提前过滤数据,减少中间计算量。统计信息滞后
视图创建后,若其依赖表的统计信息更新不及时,优化器基于视图生成计划时会使用过时数据,导致选择低效执行路径。而子查询直接基于底层表查询,会调用最新的统计信息来生成最优计划。复杂逻辑的下推限制
如果视图包含DISTINCT、聚合函数、GROUP BY或UNION等操作,优化器可能无法将外层<EXPR2>过滤条件下推到视图内部。这会导致视图先完成聚合、去重等操作生成大结果集,再做过滤;子查询形式下,优化器可以将过滤条件下推到聚合/去重之前,大幅减少待处理的数据量。
内容的提问来源于stack exchange,提问作者Eduardo

