索引视图中的COUNT_BIG

时间:2011-05-17 11:32:33

标签: sql-server

CREATE TABLE test2 (
id INTEGER,
name VARCHAR(10),
family VARCHAR(10),
amount INTEGER)

CREATE VIEW dbo.test2_v WITH SCHEMABINDING 
AS
SELECT id, SUM(amount) as amount
-- , COUNT_BIG(*) as tmp
FROM dbo.test2 
GROUP BY id

CREATE UNIQUE CLUSTERED INDEX vIdx ON test2_v(id)

我对此代码有错误:

  

无法在视图上创建索引   'test.dbo.test2_v'因为它的选择   列表不包括正确使用   COUNT_BIG。考虑添加   COUNT_BIG(*)选择列表。

我可以创建这样的视图:

CREATE VIEW dbo.test2_v WITH SCHEMABINDING 
    AS
    SELECT id, SUM(amount) as amount, COUNT_BIG(*) as tmp
    FROM dbo.test2 
    GROUP BY id

但我想知道这个专栏的目的是什么?

3 个答案:

答案 0 :(得分:15)

在这种情况下,您需要COUNT_BIG,因为您使用的是GROUP BY。

这是索引视图的许多限制之一,并且由于这些限制,索引视图不能在许多地方使用,或者它的使用效果不如预期。不幸的是,它是如何运作的。很糟糕,它缩小了使用范围。

http://technet.microsoft.com/en-us/library/cc917715.aspx

答案 1 :(得分:8)

看起来这只是SQL Server团队在SQL Server 2000中首次设计聚合索引视图时必须实施的与硬编码性能相关的限制。

直到最近,您才能在http://msdn.microsoft.com/en-us/library/aa902643(SQL.80).aspx的SQL 2000 technet文档中看到这一点,但SQL Server 2000文档已经明确废弃。您仍然可以下载92MB的PDF文件,并在第1146页和第2190页找到相关说明:https://www.microsoft.com/en-us/download/details.aspx?id=51958

可以在SQLAuthority网站上找到有关此限制的解释 - 实际上是Itzik Ben-Gan的“Inside SQL”一书的摘录:http://blog.sqlauthority.com/2010/09/21/sql-server-count-not-allowed-but-count_big-allowed-limitation-of-the-view-5/

值得注意的是 Oracle具有相同的限制/要求,原因相同(对于等效的快速可刷新物化视图);有关此主题的讨论,请参阅http://rwijk.blogspot.com.es/2009/06/fast-refreshable-materialized-view.html

解释摘要:

  • 为什么sql server逻辑上需要索引聚合视图中的物化全局计数列?
    • 这样,当更新或删除基础表的给定行时,它可以快速检查/知道聚合视图中的特定行是否需要更改或去。
  • 为什么此计数列必须为COUNT_BIG(*)
    • 这样就不存在溢出的风险;通过强制使用bigint数据类型,当特定行达到过高的计数时,不存在索引视图“破坏”的风险。

可视化计算为什么计数对于高效的聚合视图维护至关重要相对容易 - 想象以下情况:

  • 表格结构如问题
  • 中所述
  • 基础表格中有4行:

    ID  | name | family | amount
    --- | ---- | ------ | ------
    1   | a    |        | 10    
    2   | b    |        | 11    
    2   | c    |        | 12    
    3   | d    |        | 13    
    
  • 聚合视图具体化为:

    ID  | amount | tmp
    --- | ------ | ---
    1   | 10     | 1
    2   | 23     | 2
    3   | 13     | 1
    
  • 简单案例:
    • SQL引擎检测到基础数据的更改 - 删除源数据中的第三行(id 2,名称c)。
    • 引擎需要:
      • 查找并更新聚合物化视图的相关行
      • 将“金额”总和减去被删除的基础行的数量
      • 将“count”减少1(如果此列存在)
  • 目标/疑难案件:
    • SQL引擎检测到基础数据的另一个更改 - 源数据中的第二行(id 2,名称b)被删除。
    • 引擎需要:
      • 查找并删除聚合物化视图的相关行,因为没有更多源行具有相同的分组键
  • 考虑引擎在查看更新时始终具有基础表的“之前”行 - 它确切地知道在两种情况下都发生了哪些变化。
  • 物化视图维护算法中值得注意的“步骤”是确定是否需要删除目标物化集合行
    • 如果您有“计数”,则无需查看目标行以外的任何位置 - 如果您将计数降至0,则删除该行。如果您要更新任何其他值,请离开该行。
    • 如果您没有计数,那么您唯一的方法就是查询基础表以检查具有相同聚合键的任何其他行;这样的过程显然会引入更多繁重的限制:
      • 它会隐含得更慢,而且
      • 联合聚合案例中的
      • 将无法优化!

由于这些原因,count(*)列的存在是聚合物化视图实现的基本要求。 如果没有count(*)列,面对基础数据更改的聚合物化视图的实时维护将带来无法接受的高性能损失!

您仍然可以问“为什么SQL Server在创建聚合物化视图时不会自动为我创建/维护这样的计数列?” - 我没有特别好的答案。最后,我想更多的问题和混淆“如果我没有添加它,为什么我的聚合物化视图有一个BIGCOUNT列?”如果他们这样做了,那么将它作为创建对象的基本要求就更简单了,但那是纯粹的主观意见。

答案 2 :(得分:0)

我知道这个帖子有点陈旧但对于那些仍然有这个问题的人,http://technet.microsoft.com/en-us/library/ms191432%28v=sql.105%29.aspx说了关于索引视图

视图中的SELECT语句不能包含以下Transact-SQL语法元素:

AVGMAXMINSTDEVSTDEVPVARVARP汇总功能。如果在引用索引视图的查询中指定了AVG(expression),则优化程序可以在视图选择列表包含SUM(expression)COUNT_BIG(expression)时频繁计算所需结果。例如,索引视图SELECT列表不能包含表达式AVG(column1)。如果视图SELECT列表包含表达式SUM(column1)COUNT_BIG(column1),则SQL Server可以计算引用该视图并指定AVG(column1)的查询的平均值。