使用奇怪的查询优化器行为加入 SQL Server 中的视图

Posted

技术标签:

【中文标题】使用奇怪的查询优化器行为加入 SQL Server 中的视图【英文标题】:Joining against views in SQLServer with strange query optimizer behavior 【发布时间】:2010-09-29 03:21:32 【问题描述】:

我有一个复杂的视图,我用它来拉出一个主键列表,这些主键指示表中已在两个时间点之间修改的行。

此视图必须查询 13 个相关表并查看更改日志表以确定实体是否“脏”。

即使所有这些都在进行,做一个简单的查询:

select * from vwDirtyEntities;

只需 2 秒。

但是,如果我将其更改为

select
    e.Name
from 
    Entities e 
         inner join vwDirtyEntities de
             on e.Entity_ID = de.Entity_ID

这需要 1.5 分钟。

但是,如果我这样做:

declare @dirtyEntities table
(
    Entity_id uniqueidentifier;
)

insert into @dirtyEntities 
   select * from vwDirtyEntities;


select
   e.Name
from 
    Entities e 
        inner join @dirtyEntities de
           on e.Entity_ID = de.Entity_ID

我只用了 2 秒就得到了同样的结果。

这让我相信 SQLServer 在连接到实体时会评估每行的视图,而不是构建一个查询计划,将上面的单个内部连接连接到视图中的其他连接。

请注意,我想加入此视图中的完整结果集,因为它只过滤掉我在内部想要的键。

我知道我可以将它变成一个物化视图,但这将涉及绑定视图及其依赖项的架构,我不喜欢维护索引会导致的开销(此视图仅用于查询导出,而有对基础表的写入要多得多)。

那么,除了使用表变量来缓存视图结果之外,还有什么方法可以告诉 SQL Server 在评估连接时缓存视图?我尝试更改加入顺序(从视图中选择并加入实体),但这没有任何区别。

视图本身也很高效,没有优化的余地。

【问题讨论】:

【参考方案1】:

视图没有什么神奇之处。这是一个扩展的宏。优化器决定何时将视图展开到主查询中。

我将在您的帖子中解决其他问题:

您已排除索引视图。视图只有在被索引时才能是离散实体

SQL Server 永远不会自行执行 RBAR 查询。只有开发人员可以编写循环。

没有缓存的概念:每个查询都使用最新数据,除非您使用临时表

您坚持使用您认为非常有效的视图。但不知道优化器如何处理视图,它有 13 个表

SQL 是声明性的:连接顺序通常无关紧要

许多认真的 DB 开发人员不使用视图是因为以下限制:它们不可重用,因为它们是宏

编辑,另一种可能性。 Predicate pushing 在 SQL Server 2005 上。也就是说,SQL Server 无法将 JOIN 条件“更深”地推送到视图中。

【讨论】:

如果您查看 Omg Ponies 的帖子编辑历史记录,您会发现我回复了一个简单的评论(仍然存在),然后他就精神错乱了。对于上下文,这是他的原始答案:***.com/revisions/…。 这是他在我发表评论后所做的编辑:***.com/revisions/…。我从来没有攻击过他,他开始发疯了。 关于加入顺序无关紧要。这在理论上可能是正确的,但在实践中,我已经看到明确地重新排序连接是有益的,通常是因为它允许数据库在评估其他连接之前丢弃不匹配的更大数据集。 另外,我完全知道视图是一个宏。但是,我不明白为什么非宏版本(我的问题中没有显示)远远优于视图版本。显然,对于 SQLServer,视图不仅仅是宏。 顺便说一句,我对你的回答投了赞成票,因为你提供了有用的回答并在回答之前完整阅读了我的问题。

以上是关于使用奇怪的查询优化器行为加入 SQL Server 中的视图的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 中全文搜索的奇怪行为

提高sql server查询优化器结果的方法

选择 * 和查询优化器

奇怪的 MS SQL Server 行为/性能问题

SQL -- SQL Server 查询优化器(Query Optimizers)

从 SQL Server 查询优化器生成多个脚本