Using indexed views for aggregates - too good to be true?

As you've noted, the view itself only materializes a small number of rows - so even if you update the whole table, the additional I/O involved with updating the view is negligible. You probably already felt the biggest pain you're going to feel when you created the view. The next closest will be if you add a gazillion rows to the base table with a bunch of new IDs that require new rows in the view.

This isn't too good to be true. You're using indexed views exactly how they were meant to be used - or at least one of the most effective ways: to pay for future query aggregations at write time. This works best when the result is much smaller than the source and of course when the aggregations are requested more often than the underlying data is updated (more common in DW than OLTP, generally).

Unfortunately many people think indexing a view is magic - an index won't make all views more efficient, especially views that simply join tables and/or produce the same number of rows as the source (or even multiply). In these cases the I/O from the view is the same or even worse than the original query, not only because there are the same or more rows, but often they are storing and materializing more columns, too. So materializing those in advance doesn't provide any gains, since - even with SSDs - I/O, network, and client processing/rendering still remain the primary bottlenecks in returning large resultsets to the client. The savings you get in avoiding the join at runtime just aren't measurable in comparison to all the other resources you're still using.

Like non-clustered indexes, just be careful to not over-do it. If you add 10 different indexed views to one table, you're going to see more impact to the write portion of your workload, especially if the grouping column(s) are not (in) the clustering key.

Gosh, I've been meaning to blog about this topic.


Aarons answers covered this question well. Two things to add:

  1. Aggregation indexed views can lead to cross-row contention and deadlocks. Normally, two inserts do not deadlock (except for rather rare conditions such as lock escalation or lock hash collisions). But if both inserts address the same group in the view they will contend. The same point stands for anything else that takes locks (DML, lock hints).
  2. Indexed views that do not aggregate can be useful as well. They allow you to index on columns from multiple tables. That way you can efficiently filter on one table and order by a column from a joined table. That pattern can convert full-table join to tiny constant-time queries.

I have used both aggregation and join views with extreme benefit.

All in all your use case seems like a perfect case. Indexed views are a technique far underutilized.