As I understand it SQL views represent 'a virtual table' where the data is actually held in other 'backing tables' the view references. Indexes can be added to views to improve performance, but what do these indexes actually reference if the view is just a virtual table? (is it a primary key on backing table or something?)
Imagine a view represented by SELECT * FROM bookings WHERE IsDeleted=0 with a index on bookings.AppointmentDate ... The index could possibly be ordered by appointment date (for easy searching) and each index leaf hold the row number of where that data is in the view ... That would work ... Until bookings changes and some deleted booking gets un-deleted now what the proposed index would hold would be miss-aligned.
Another way would be to have the indexed view now actually be 'doppleganger' of the bookings table, so its materialised and not virtual anymore. Now the index can refer to whatever primary key the doppleganger has, so nothing breaks when bookings get un-deleted. but again if the booking table changes, this doppleganger has to 'spot' new rows that it should have (like the un-deleted booking) and ones it needs to remove from itself before returning a result, wouldn't that be expensive on table updates negating the possible benefit of using the indexed view?
I'm trying to understand how indexed views really work under the hood.
In SQL Server, indexed views store copies of all of the data for the view1, very much like another table. The difference is in how that data gets updated.
Effectively, the server generates triggers (but they don't show up as such) on each of the base tables to maintain the data in the view's clustered index. This is why there are many restrictions on what features an indexed view supports - they have to allow these "triggers" to be auto-generated to maintain the view data just based on the
insertedanddeletedpseudo-tables.So, for instance, this is why you cannot use the
MAXaggregate in an indexed view. Whilst you can write an efficientinserttrigger to deal with any new values larger that the currentMAX,updateordeletetriggers would potentially have to rescan the entire base table again, if the current max value were changed or removed.1This means that if your query supports it, either because you've used the
NOEXPANDhint or you're on Enterprise Edition and the optimizer likes it, a query can just use the data in the view without accessing the base table data at all.