背景
大家好!
我最近了解到,在较新版本的Server中,查询优化器可以“扩展”SQL视图,并利用内联性能优势。这可能会对我创建哪些类型的数据库对象以及创建它们的原因和时间产生一些重大影响,这取决于什么时候实现了增强的性能,什么时候没有。
例如,当我只需要在调用查询的底部创建一个视图和一个WHERE
语句时,我就不会麻烦地为一个非常大的事务表(性能非常重要)创建一个参数化内联表值函数和一个开始日期参数和一个结束日期参数。
SELECT
Column1
FROM vw_Simple
WHERE
Column1 BETWEEN @SomeStartDate AND @SomeEndDate
并且相信查询优化器会“扩展”视图,并给我一个很好的执行计划。
注意:我说的是一个简单的、非嵌套的、非索引的Server视图。有点像
CREATE VIEW vw_Simple
AS
SELECT
Column1
,Column2
FROM TableA
问题
我的问题是:了解查询优化器何时可以“展开”SQL视图以及何时不能展开SQL视图的确切指导方针是什么?
我在微软的官方文档中找不到这个答案。
到目前为止我所发现的
查询优化器可以展开视图的情况:
查询优化器无法展开视图的情况:
灰度区
发布于 2021-06-14 22:03:20
您不会在文档中找到这些信息,因为--它不是单个特性本身--它只是编译器/优化器在不同阶段完成查询,使用了许多不同的技术来获得最佳的执行计划。有时它可以安全地通过谓词,有时它不能。
请注意,“扩展视图”在这里是错误的。视图总是扩展到它的定义中(NOEXPAND
除外)。您所指的是谓词下推。
编译期间视图会发生什么情况?
,我在这里假设没有使用索引视图和
NOEXPAND
。
在执行查询时,编译器首先解析查询并将其命名为基本的执行计划。这是一个非常粗糙的、未优化的版本,它很大程度上反映了所编写的查询。
当查询中有视图时,编译器将检索视图的预解析执行树,并将其插入执行计划中,这也是一个非常粗略的草案。
对于派生表、CTE、关联子查询和不相关子查询以及内联TVF,也会发生相同的情况,但也需要解析。
在这一点之后,您可以假设视图可能已经编写为CTE,这没有什么区别。
优化器能推送视图吗?
编译器有很多技巧,谓词下推就是其中之一,简化视图也是其中之一。
这里的编译器的能力主要取决于它是否能够推断是否允许简化,而不是它是否可能。
例如,这个查询
SELECT SomeCol
FROM (
SELECT TOP 100 PERCENT *
FROM (
SELECT SomeCol, OtherCol, 1 / 0 AS ThisDoesntError
FROM table1
) t
WHERE OtherCol = 1
ORDER BY ThisDoesntError
) t
WHERE OtherCol <> 2
对此进行优化是相当简单的
SELECT SomeCol
FROM table1
WHERE OtherCol = 1
因为众所周知,TOP 100 PERCENT... ORDER BY...
对外部查询没有任何影响,因此可以删除,然后是整个ThisDoesntError
列。
那它什么时候不起作用?
当优化器无法推送视图时,问题就开始了,因为它可能会更改查询的语义(因此也会改变结果)。
SELECT SomeCol
FROM (
SELECT TOP 10 *
FROM (
SELECT SomeCol, OtherCol, 1 / 0 AS ThisDOESError
FROM table1
) t
ORDER BY ThisDOESError
) t
WHERE OtherCol = 1
因为需要根据TOP
子句计算ORDER BY ThisDOESError
,所以不能省略列ThisDOESError
,不能推送OtherCol
上的筛选器。
同样地,这个也不能被优化。
SELECT SomeCol
FROM (
SELECT SomeCol, OtherCol,
ROW_NUMBER() OVER (PARTITION BY SomeCol ORDER BY ThirdCol) AS rn
FROM table1
) t
WHERE rn = 1 AND OtherCol = 1
在这种情况下,由于必须在整个集合上计算行号,所以不能安全地推送筛选器OtherCol = 5
。
非常有趣,这个版本应该能够安全地通过(尽管没有承诺!)
SELECT SomeCol
FROM (
SELECT SomeCol, OtherCol,
ROW_NUMBER() OVER (PARTITION BY SomeCol ORDER BY ThirdCol) AS rn
FROM table1
) t
WHERE rn = 1 AND SomeCol = 'Something'
在这种情况下,优化器理论上应该能够看到过滤列也是分区列,因此行号计算不会改变。
https://stackoverflow.com/questions/67975467
复制相似问题