将索引视图用于聚合-太好了以至于无法实现?


28

我们有一个数据仓库,它的记录数很大(10-20百万行),并且经常运行查询来对某些日期之间的记录进行计数,或者对带有某些标志的记录进行计数,例如

SELECT
    f.IsFoo,
    COUNT(*) AS WidgetCount
FROM Widgets AS w
JOIN Flags AS f
    ON f.FlagId = w.FlagId
WHERE w.Date >= @startDate
GROUP BY f.IsFoo

性能并不是很糟糕,但可能会相对缓慢(在冷缓存中可能为10秒)。

最近,我发现我可以GROUP BY在索引视图中使用,因此尝试了类似于以下内容的操作

CREATE VIEW TestView
WITH SCHEMABINDING
AS
    SELECT
        Date,
        FlagId,
        COUNT_BIG(*) AS WidgetCount
    FROM Widgets
    GROUP BY Date, FlagId;
GO

CREATE UNIQUE CLUSTERED INDEX PK_TestView ON TestView
(
    Date,
    FlagId
);

结果,我的第一个查询的性能现在为<100ms,结果视图和索引为<100k(尽管我们的行数很大,但日期和标志ID的范围意味着该视图仅包含1000-2000行)。

我以为这可能会削弱对Widget表的写入性能,但是不会-就我所知,对该表的插入和更新性能几乎不受影响(此外,作为数据仓库,该表很少更新无论如何)

对我来说,这似乎太不可思议了-是吗?以这种方式使用索引视图时,我需要注意什么?


2
您可以重写脚本,使它们实际上是有效的SQL吗?您SELECTCREATE VIEW脚本是错误的,因为我认为您的脚本是错误的CREATE INDEX
马克·辛金森

2
@MarkSinkinson Apologies证明,尝试为虚表编写有效的SQL很困难
Justin

当我想要更高级的视图时(例如包含MAX,自联接或外部联接的视图,或索引本身引用了另一个视图的视图),对我而言,“太好了”这一部分来了-至少在SQL Server中所有这些都不是允许docs.microsoft.com/zh-cn/sql/relational-databases/views/…。因此,我总是最终变得过于野心勃勃,然后不得不缩小规模。但是对于更简单的聚合来说,它们确实很棒-甚至支持SUM。
Simon_Weaver

Answers:


29

正如您已经指出的,视图本身只包含少量的行-因此,即使您更新整个表,更新视图所涉及的其他 I / O也可以忽略不计。创建视图时,您可能已经感受到了最大的痛苦。下一个最接近的是如果您向基表中添加了几百亿行,其中包含一堆需要在视图中添加新行的新ID。

这不是太好了。您正在使用索引视图准确地使用它们-或至少是最有效的方法之一:在写入时为将来的查询聚合付费。当结果远小于源时,当然,当请求聚合的次数比更新基础数据的次数更多时(在DW中通常比OLTP更常见),这最有效。

不幸的是,许多人认为为视图建立索引是神奇的-索引不会使所有视图更有效,尤其是仅连接表和/或产生与源相同数量(甚至是相乘)的行的视图。在这些情况下,视图中的I / O与原始查询相同或什至更差,这不仅是因为存在相同或更多的行,而且通常它们还存储并实现了更多的列。因此,提前实现这些目标不会带来任何收益,因为-即使使用SSD,I / O,网络和客户端处理/渲染仍然是将大型结果集返回给客户端的主要瓶颈。与您仍在使用的所有其他资源相比,避免在运行时加入联接所节省的成本无法衡量。

像非聚集索引一样,请小心不要过度使用它。如果将10个不同的索引视图添加到一个表中,将会对工作量的写入部分产生更多影响,特别是如果分组列不在集群键中。

天哪,我一直想写关于这个话题的博客。


19

Aarons的回答很好地涵盖了这个问题。要添加的两件事:

  1. 聚集索引视图可能导致跨行争用和死锁。通常,两个插入不会死锁(除了极少数情况,例如锁升级或锁哈希冲突)。但是,如果两个插入都在视图中指向同一组,则它们将争用。同一点代表任何其他需要锁定的东西(DML,锁定提示)。
  2. 未聚合的索引视图也可能很有用。它们使您可以索引多个表中的列。这样,您可以有效地对一个表进行筛选,并按联接表中的列进行排序。这种模式可以将全表联接转换为微小的恒定时间查询。

我使用聚合和加入视图都具有极大的好处。

总而言之,您的用例似乎是一个完美的案例。索引视图是一种未被充分利用的技术。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.