索引视图中的COUNT_BIG

dem*_*mas 24 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)
Run Code Online (Sandbox Code Playgroud)

我有这个代码的错误:

无法在视图'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
Run Code Online (Sandbox Code Playgroud)

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

San*_*ddy 15

在这种情况下,您需要COUNT_BIG,因为您正在使用GROUP BY.

这是索引视图的许多限制之一,并且由于这些限制,索引视图不能在许多地方使用,或者它的使用不如它本来有效.不幸的是,它是如何运作的.糟透了,它缩小了使用范围.

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

  • 它可以防止SQL Server在删除操作期间执行表扫描.如果我从表中删除了14个具有相同ID的行,并且这使得SUM()表达式等于0,那是否意味着a)只有14行具有该ID,从索引中删除它,或者b)还有剩余的行表中具有此ID的行,但其数量列为SUM?如果它可以查看COUNT_BIG,它可以立即回答该问题. (10认同)

Tao*_*Tao 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 -丁COUNT_BIG-允许-限制的最-视图- 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    
    
    Run Code Online (Sandbox Code Playgroud)
  • 聚合视图具体化为:

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

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

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