cro*_*sek 7 sql-server execution-plan view cross-apply
我们有一个针对单项查询优化的视图(200 毫秒无并行性):
select *
from OptimizedForSingleObjectIdView e2i
where ObjectId = 3374700
Run Code Online (Sandbox Code Playgroud)
它也适用于一小组静态 ID(~5)。
select *
from OptimizedForSingleObjectIdView e2i
where ObjectId in (3374700, 3374710, 3374720, 3374730, 3374740);
Run Code Online (Sandbox Code Playgroud)
但是,如果对象来自外部源,那么它会生成一个缓慢的计划。执行计划显示视图部分的执行分支忽略了 ObjectId 上的谓词,而在原始情况下,它使用它们来执行索引查找。
select v.*
from
(
select top 1 ObjectId from Objects
where ObjectId % 10 = 0
order by ObjectId
) o
join OptimizedForSingleObjectIdView v -- (also tried inner loop join)
on v.ObjectId = o.ObjectId;
Run Code Online (Sandbox Code Playgroud)
我们不希望投资于“双重”优化非奇异情况的视图。相反,我们“寻求”的解决方案是对每个对象重复调用一次视图,而无需求助于 SP。
大多数情况下,以下解决方案会逐行调用视图。但是这次不是,甚至不是只有 1 个对象:
select v.*
from
(
select top 1 ObjectId
from Objects
where ObjectId % 10 = 0 -- non-trivial predicate
order by ObjectId
) o
cross apply
(
select top 2000000000 *
from OptimizedForSingleObjectIdView v_
where ObjectId = o.ObjectId
order by v_.SomeField
) v;
Run Code Online (Sandbox Code Playgroud)
有一次,我认为有一种说法是,当它调用 UDF 时,可以保证按行执行交叉应用,但这也失败了:
create function FunctionCallingView(@pObjectId bigint)
returns table
as
return select *
from OptimizedForSingleObjectIdView
where ObjectId = @pObjectId;
select v.*
from
(
select top 1 ObjectId
from Objects
where ObjectId % 10 = 0
order by ObjectId
) o
cross apply FunctionCallingView(o.ObjectId) v
Run Code Online (Sandbox Code Playgroud)
添加选项(强制顺序)没有帮助——但是视图中已经有两个哈希提示。暂时移除它们并没有帮助并减慢了单个案例的速度。
这是基于函数的慢速案例的估计计划的片段。1 行的估计是正确的。最右边(未显示)是一个不包括前 1 个结果的搜索谓词。这似乎与我们遇到的其他情况类似,其中来自表查找的奇异探测值不用作其他地方的查找谓词。
Pau*_*ite 10
如果不使用引入新 T-SQL 执行范围的东西,例如非内联(多语句)表值函数,就不可能完全保证评估外部查询的每一行的视图BEGIN...END
。这几乎是在回答您之前的问题如何使用合并提示来隔离 SQL Server 中的复杂查询时给出的建议。
有一次,我认为有一种说法是,当它调用 UDF 时,可以保证逐行执行交叉应用
这不适用于内联表值函数,因为在优化开始之前,定义已扩展到调用查询中。
也就是说,您可以做一些事情来强烈鼓励预期的结果。
执行计划显示视图部分的执行分支忽略谓词 on
ObjectId
而在原始情况下它使用它们来执行索引查找。
您期望ObjectId
使用每个驱动行的索引查找“在视图内”评估值。这是相关的嵌套循环连接(应用)执行方式。请注意,使用APPLY
T-SQL 语言元素并不能保证物理执行将使用应用样式。
听起来好像 SQL Server 选择使用ObjectId
在Nested Loops Join运算符中测试的值来执行。这是一个不相关的或简单的嵌套循环连接执行模式。
这很可能是由您在视图中使用的连接提示引起的。通常应避免使用联接提示,因为它们极大地限制了优化器的自由度,而不仅仅是联接的物理类型。特别是,连接提示还强制整个查询的连接顺序(就像您使用了FORCE ORDER
提示一样)并阻止与聚合放置和策略相关的多项优化,以及除此之外的许多其他优化。
如果您确实必须在视图中加入连接提示(我强烈建议您通常避免这种情况),您可能会发现获得所需计划形状的最可靠方法是:
RETURNS TABLE
) 函数。@ObjectId
作为函数的参数提供。FORCESEEK
表提示里面的函数可以使用,如果真的每次使用应导致所追求的。APPLY
。我通常不喜欢使用特定的语法和提示来试图强制某种物理计划形状。通过参数化查询并使用计划指南保证计划形状,您可能会取得更大的成功。
归档时间: |
|
查看次数: |
1021 次 |
最近记录: |