为什么在索引视图上带有索引的计算日期时间列的 WHERE 子句会在原始表上寻找聚集索引

Fab*_*all 5 sql-server materialized-view azure-sql-database

首先,抱歉标题太长。

设置

我将示例减少到最少,以使其更清晰,因此不再有有意义的语义。

DBMS:Azure SQL 数据库 V12

假设有下表:

CREATE TABLE [dbo].[MuchDataTable](
    [SmallDateTimeColumn] [smalldatetime] NOT NULL
)

GO
CREATE CLUSTERED INDEX [IX_MuchDataTable_SmallDateTimeColumn] ON [MuchDataTable] ([SmallDateTimeColumn])
Run Code Online (Sandbox Code Playgroud)

现在我想获取特定于任意天数范围的聚合数据。由于该表包含很多行(超过 150 Mio。)我创建了一个索引视图,它基本上如下所示:

CREATE VIEW [dbo].[AggregatedDateView]
    WITH SCHEMABINDING
AS
    SELECT CONVERT(DATE, [SmallDateTimeColumn]) AS [DateColumn], COUNT_BIG(*) AS [Count]
    FROM [dbo].[MuchDataTable]
    GROUP BY CONVERT(DATE, [SmallDateTimeColumn])

GO
CREATE UNIQUE CLUSTERED INDEX [IX_AggregatedDateView_Date] ON [dbo].[AggregatedDateView] ([DateColumn])
Run Code Online (Sandbox Code Playgroud)

对于我的一天分组,我将每个都转换DateTimeDate. 然后我在视图上创建一个聚集索引。

问题

对视图执行简单的 SELECT * 扫描视图的索引。没关系:

SELECT * FROM [AggregatedDateView] 的执行计划

但是,如果我在计算日期列上使用 WHERE 约束进行查询,则会对原始表执行聚集索引查找:

SELECT * FROM [AggregatedDateView] WHERE [DateColumn] = '2016-05-20' 的执行计划

问题

我的理解是,应该有一个 B 树,其中包含索引视图的所有转换日期。SQL Server 为什么选择扫描底层表的聚集索引?这对索引视图是不可能的,我必须在触发器和普通表之上构建解决方案吗?

编辑:为了更清楚地说明,一旦扫描了一系列日期,它就会成为一个真正的问题,所以像

SELECT * FROM [AggregatedDateView] WHERE [DateColumn] > '2016-05-20' AND [DateColumn] < '2016-08-20'
Run Code Online (Sandbox Code Playgroud)

这里扫描了超过 3 个月的索引,这对我来说已经很多了。

Mik*_*son 4

SQL Server 扩展视图并考虑访问基表。是否使用视图或基表是优化器基于成本的决定。

要强制 SQL Server 使用索引视图,您应该使用noexpand提示。

SELECT * 
from [AggregatedDateView] WITH(NOEXPAND) 
where [DateColumn] > '2016-05-20' AND 
      [DateColumn] < '2016-08-20'
Run Code Online (Sandbox Code Playgroud)