【问题标题】:Indexing views with a CTE使用 CTE 索引视图
【发布时间】:2013-03-16 19:28:49
【问题描述】:

所以,我刚刚发现 SQL Server 2008 不允许您在定义中为带有 CTE 的视图编制索引,但它允许您通过 alter 查询在视图定义中添加 with schemabinding。这有充分的理由吗?出于某种我不知道的原因,这是否有意义?我的印象是WITH SCHEMABINDINGs 的主要目的是让你索引一个视图

新的和改进的更多查询操作

;with x
as
(
    select   rx.pat_id
            ,rx.drug_class
            ,count(*) as counts
            from rx
            group by rx.pat_id,rx.drug_class

)
select   x.pat_id
        ,x.drug_class
        ,x.counts
        ,SUM(c.std_cost) as [Healthcare Costs]
    from x
    inner join claims as c
    on claims.pat_id=x.pat_id
    group by x.pat_id,x.drug_class,x.counts

以及创建索引的代码

create unique clustered index [TestIndexName] on [dbo].[MyView]
( pat_id asc, drug_class asc, counts asc)

【问题讨论】:

  • 顺便说一句,即使可以为此视图编制索引,聚合列 (counts) 也不应该是唯一索引定义的一部分。

标签: sql sql-server tsql view common-table-expression


【解决方案1】:
  1. 不能用 CTE 索引视图。即使视图可以拥有SCHEMABINDING。这样想吧。为了索引视图,它必须满足两个条件(以及许多其他条件):(a)它已被创建WITH SCHEMABINDING 和(b)它不包含 CTE。为了对视图进行模式绑定,它确实不需要需要满足它不包含 CTE 的条件。

  2. 我不相信存在这样一种情况,即视图具有 CTE 并且将从被索引中受益。这与您的实际问题无关,但我的直觉是您正试图索引此视图以神奇地使其更快。索引视图不一定比对基表的查询快 - 存在限制是有原因的,并且只有特定的用例才有意义。请注意不要盲目地将您的所有视图索引为神奇的“更快”按钮。还要记住,索引视图需要维护。因此,它会增加工作负载中影响基表的所有 DML 操作的成本。

  3. Schemabinding 仅用于索引视图。也可以使用 在诸如 UDF 之类的东西上以帮助说服确定性,可用于 用于防止更改底层架构的视图和函数,以及 在某些情况下,它可以提高性能(例如,当 UDF 是 不是模式绑定的,优化器可能必须创建一个表假脱机来 处理任何底层 DDL 更改)。所以请不要认为它是 奇怪的是,您可以模式绑定视图,但不能对其编制索引。 索引视图需要它,但关系不是相互的。


对于您的具体情况,我建议这样做:

CREATE VIEW dbo.PatClassCounts
WITH SCHEMABINDING
AS
  SELECT pat_id, drug_class, 
      COUNT_BIG(*) AS counts
    FROM dbo.rx
    GROUP BY pat_id, drug_class;
GO
CREATE UNIQUE CLUSTERED INDEX ON dbo.PatClassCounts(pat_id, drug_class);
GO
CREATE VIEW dbo.ClaimSums
WITH SCHEMABINDING
AS
  SELECT pat_id, 
    SUM(c.std_cost) AS [Healthcare Costs], 
    COUNT_BIG(*) AS counts
  FROM dbo.claims
  GROUP BY pat_id;
GO
CREATE UNIQUE CLUSTERED INDEX ON dbo.ClaimSums(pat_id);
GO

现在您可以创建一个仅在这两个索引视图之间进行连接的非索引视图,并且它将利用索引(您可能必须在较低版本上使用NOEXPAND,不确定):

CREATE VIEW dbo.OriginalViewName
WITH SCHEMABINDING
AS
    SELECT p.pat_id, p.drug_class, p.counts, c.[Healthcare Costs]
      FROM dbo.PatClassCounts AS p
      INNER JOIN dbo.ClaimSums AS c
      ON p.pat_id = c.pat_id;
GO

现在,这一切都假定预先聚合这些信息是值得的 - 如果您不经常运行此查询,但数据被修改了很多,最好不要创建索引视图。

另请注意,ClaimSums 视图中的SUM(std_cost) 对于每个pat_id + drug_class 组合都是相同的,因为它仅聚合到pat_id。我猜claims 表中可能有一个drug_class 也应该是连接标准的一部分,但我不确定。如果是这样的话,我认为这可以折叠为单个索引视图。

【讨论】:

  • 任何拉取跨服务器数据的视图都将无法建立索引,这是非常合理的,因为您无法索引不总是存在的内容。我想知道 OP 是否有一些 rpc 调用,所以没有发布代码。
  • @RandomUs1r 我认为情况并非如此,因为 OP 能够更改视图并添加 SCHEMABINDING。如果它引用了三部分或四部分的名称,这应该是不可能的。
  • 当我尝试在我想要架构绑定的视图中使用 CTE 时,我收到了错误 Cannot create index on MyDatabase because it references a CTE. Views referencing CTEs cannot be indexed Level 16...无论级别 16 是什么意思。我正在使用 SSM
  • @AaronBertrand 你的直觉是对的,我试图让它更快。另外学习一些,我从来没有尝试过索引视图,只是想亲自动手。
  • 您应该从阅读Designing Indexed Views 之类的内容开始,而不是仅仅尝试为您现有的某些视图添加索引,并希望它能够使其更快。它们通常用于预聚合 COUNT()SUM() 等内容,而不仅仅是为了更快地对视图进行查询。
猜你喜欢
  • 1970-01-01
  • 2010-11-02
  • 2016-10-19
  • 1970-01-01
  • 2011-12-16
  • 2012-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多