【问题标题】:SQL Server Views | Inline View Expansion GuidelinesSQL Server 视图 |内联视图扩展指南
【发布时间】:2021-08-30 16:01:30
【问题描述】:

背景

大家好!

我最近了解到,在较新版本的 SQL Server 中,查询优化器可以“扩展” SQL 视图并利用内联性能优势。这可能会对我创建哪种类型的数据库对象以及创建它们的原因和时间产生一些重大影响,具体取决于何时实现这种增强的性能以及何时没有实现。

例如,我不会费心为一个非常大的事务表(性能非常重要)创建一个带有开始日期参数和结束日期参数的参数化内联表值函数调用查询底部的WHERE 语句,类似于

SELECT
     Column1
FROM vw_Simple
WHERE
     Column1 BETWEEN @SomeStartDate AND @SomeEndDate

并相信查询优化器会“扩展”视图并为我提供出色的执行计划。

注意:我说的是一个简单的、非嵌套的、非索引的 SQL Server 视图。类似的东西

CREATE VIEW vw_Simple
AS
SELECT
    Column1
    ,Column2
FROM TableA

问题

我的问题是:了解查询优化器何时可以“扩展”SQL 视图以及何时不能的确切指南是什么?

我在微软官方文档中找不到这个答案。

到目前为止我发现了什么

查询优化器可以展开视图的情况:

查询优化器无法展开视图的情况:

灰色地带

【问题讨论】:

  • 对于它的价值,如果您右键单击查询并选择显示实际执行计划,SSMS 会显示实际执行计划。而且,如果查询优化器检测到它需要索引,它会告诉您它需要什么索引。

标签: sql sql-server view query-optimization sql-execution-plan


【解决方案1】:

您不会在文档中找到此信息,因为它本身并不是一个单独的功能,它只是编译器/优化器通过查询工作在各个阶段,使用多种不同的技术来获得最佳执行计划。有时它可以安全地通过谓词,有时却不能。

请注意,“扩展视图” 在这里是错误的术语。视图总是扩展为它的定义(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'

在这种情况下,优化器理论上应该能够看到过滤列也是分区列,因此行数计算不会改变。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-12-04
    • 2019-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多