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

时间:2010-09-29 03:21:33

标签: sql-server tsql views

我有一个复杂的视图,用于提取主键列表,指示表中已在两个时间点之间修改的行。

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

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

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 个答案:

答案 0 :(得分:5)

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

我会在你的帖子中提到其他要点:

  • 您排除了索引视图。视图在索引时只能是一个离散的实体

  • SQL Server永远不会对它自己进行RBAR查询。只有开发人员才能编写循环。

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

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

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

  • 许多严肃的数据库开发人员因为这样的限制而不使用视图:它们不可重用,因为它们是宏

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