Sql server 索引视图中的大计数

Sql server 索引视图中的大计数,sql-server,Sql Server,我对该代码有错误: 无法在视图上创建索引 'test.dbo.test2_v',因为它的 列表中不包括正确使用 数一数。考虑加入 计数大(*)以选择列表 我可以创建如下视图: 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 a

我对该代码有错误:

无法在视图上创建索引 'test.dbo.test2_v',因为它的 列表中不包括正确使用 数一数。考虑加入 计数大(*)以选择列表

我可以创建如下视图:

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)
ID  | name | family | amount
--- | ---- | ------ | ------
1   | a    |        | 10    
2   | b    |        | 11    
2   | c    |        | 12    
3   | d    |        | 13    

但我只是想知道,在这种情况下,本专栏的目的是什么?

在这种情况下,由于您使用的是GROUP BY,所以您需要大计数

这是索引视图的许多限制之一,由于这些限制,索引视图不能在许多地方使用,或者使用效果不如它本来可以发挥的那样好。不幸的是,这是它目前的工作方式。糟透了,它缩小了使用范围


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

直到最近,您还可以在的SQL 2000 technet文档中看到这一点,但是SQL Server 2000文档肯定已经过时了。您仍然可以下载92MB的PDF文件,并在第1146页和第2190页找到相关注释:

有关此限制的解释可以在SQLAuthority网站上找到——实际上是伊齐克·本·甘的《SQL内部》一书的摘录:

值得注意的是,Oracle具有相同的限制/要求,原因相同(用于等效的快速刷新物化视图);有关此主题的讨论,请参阅

解释摘要:

  • 为什么sql server逻辑上需要索引聚合视图中的物化全局计数列?
    • 这样,当更新或删除基础表的给定行时,它可以快速检查/知道聚合视图中的特定行是否需要更改或转到
  • 为什么此计数列需要是
    count\u BIG(*)
    • 因此,不存在可能的溢出风险;通过强制使用bigint数据类型,当特定行达到过高计数时,索引视图没有“中断”的风险
可以相对容易地可视化为什么计数对于有效的聚合视图维护至关重要-想象以下情况:

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

    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 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)
    
    ID  | name | family | amount
    --- | ---- | ------ | ------
    1   | a    |        | 10    
    2   | b    |        | 11    
    2   | c    |        | 12    
    3   | d    |        | 13    
    
  • 简单案例:
    • SQL引擎检测到基础数据中的更改—源数据中的第三行(id 2,名称c)被删除
    • 发动机需要:
      • 查找并更新聚合物化视图的相关行
      • 将“金额”总和减去已删除的基础行的金额
      • 将“计数”减少1(如果此列存在)
  • 目标/疑难案例:
    • SQL引擎检测到基础数据中的另一个更改—源数据中的第二行(id 2,名称b)被删除
    • 发动机需要:
      • 查找并删除聚合物化视图的相关行,因为不再有具有相同分组键的源行
  • 考虑到引擎在视图更新时总是有基础表的“before”行,它确切地知道在这两种情况下发生了什么变化
  • 物化视图维护算法中值得注意的“步骤”是确定是否需要删除目标物化聚合行
    • 如果您有一个“count”,则不需要查看目标行以外的任何位置-如果您将计数降至0,则删除该行。如果要更新为任何其他值,请保留该行
    • 如果没有计数,那么唯一的计算方法是查询基础表,以检查具有相同聚合键的任何其他行;这一过程显然会带来更为繁重的限制:
      • 这将意味着更慢,而且
      • 在连接聚合情况下,将无法优化
由于这些原因,count(*)列的存在是聚合物化视图实现的基本要求如果没有count(*)列,在底层数据更改时实时维护聚合物化视图将带来不可接受的高性能损失


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

我知道这条线索有点陈旧,但对于那些仍然有这个问题的人来说,这是关于索引视图的

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

AVG
MAX
MIN
STDEV
STDEVP
VAR
,或
VARP
聚合函数。如果在引用索引视图的查询中指定了
AVG(expression)
,那么如果视图选择列表包含
SUM(expression)
COUNT\u BIG(expression)
,则优化器可以经常计算所需的结果。例如,索引视图
SELECT
列表不能包含表达式
AVG(column1)
。如果视图
SELECT
列表包含表达式
SUM(column1)
COUNT\u BIG(column1)
,SQL Server可以计算引用视图和指定的查询的平均值