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

Fly*_*wat 6 t-sql sql-server views

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

此视图必须查询13个相关表并查看changelog表以确定实体是否"脏".

即使完成了所有这些,也可以进行简单的查询:

select * from vwDirtyEntities;
Run Code Online (Sandbox Code Playgroud)

只需2秒.

但是,如果我将其更改为

select
    e.Name
from 
    Entities e 
         inner join vwDirtyEntities de
             on e.Entity_ID = de.Entity_ID
Run Code Online (Sandbox Code Playgroud)

这需要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
Run Code Online (Sandbox Code Playgroud)

我在2秒钟内得到了相同的结果.

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

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

我知道我可以将它变成物化视图,但是这将涉及到视图及其依赖关系的模式绑定,我不喜欢维护索引会导致的开销(此视图仅针对导出进行查询,而有更多写入到基础表).

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

视图本身也非常高效,并且没有优化空间.

gbn*_*gbn 5

一个观点没有什么神奇之处.这是一个扩展的宏.优化器决定何时JOINed将视图扩展为主查询.

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

  • 你已经排除了索引视图.视图在索引时只能是离散实体

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

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

  • 你坚持使用你认为非常有效的观点.但是不知道优化器如何处理视图,它有13个

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

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

编辑,另一种可能性.谓词推送 SQL Server 2005.也就是说,SQL Server无法将JOIN条件"更深"地推送到视图中.