1. Indexed Views
An indexed view is any view that has a clustered index defined on it. When a CREATE INDEX
statement is executed on a view, the result set for the view is
materialized and stored in the database with the same structure as a
table with a clustered index. Changes made to the data in the underlying
tables of the view are automatically reflected in the view the same way
any changes to a table are reflected in its indexes. In addition to a
clustered index, you can create additional nonclustered indexes on
indexed views to provide additional query performance. Additional
indexes on views might provide more options for the Query Optimizer to
choose from during the optimization process.
In the Developer and Enterprise Editions of SQL
Server 2008, when an indexed view exists on a table and you access the
view directly within a query, the Query Optimizer automatically
considers using the index on the view to improve query performance, just
as an index on a table is used to improve performance. The Query
Optimizer also considers using the indexed view, even for queries that
do not directly name the view in the FROM clause. In other
words, when a query might benefit from using the indexed view, the Query
Optimizer can use the indexed view to satisfy the query in place of an
existing index on the table itself.
It is important to note that although indexed views
can be created in all editions of SQL Server 2008, only the Developer
and Enterprise Editions automatically use indexed views to optimize
queries. In the other editions, indexed views are not used to improve
query performance unless the view is explicitly specified in the query
and the NOEXPAND hint is specified as well. Without the NOEXPAND
hint, SQL Server expands the view to its underlying base tables and
optimizes based on the table indexes. The following example shows the
use of the NOEXPAND option to force SQL Server to use the indexed view specified in the query:
select * from sales_Qty_Rollup WITH (NOEXPAND)
where stor_id between 'B914' and 'B999'SET ARITHABORT ON
Indexed views add overhead and can be more complex
for SQL Server to maintain over time than normal indexes. Each time an
underlying table of a view is modified, SQL Server has to update the
view result set and potentially the index on that view. The scope of a
view’s index can be larger than that of any single table’s index,
especially if the view is defined on several large tables. The overhead
associated with maintaining a view and its index during updates can
negate any benefit that queries gain from the indexed view. Because of
this additional maintenance overhead, you should create indexes only on views where the advantage provided by the improved speed in retrieving the results outweighs the increased maintenance overhead.
Following are some guidelines to consider when you design indexed views:
- Create indexes on views where the underlying table data is relatively static.
- Create indexed views that will be used by several queries.
- Keep the indexes small. As with table indexes, a smaller index allows SQL Server to access the data more efficiently.
- Create
indexed views that will be significantly smaller than the underlying
table(s). An indexed view might not provide significant performance
gains if its size is similar to the size of the original table.
- You need to specify the NOEXPAND
hint in editions of SQL Server other than the Developer and Enterprise
Editions of SQL Server; otherwise, the indexed view is not used to
optimize the query.
2. Indexes on Computed Columns
SQL Server 2008 allows you to build indexes on
computed columns in your tables. Computed columns can participate at any
position of an index, along with your other table columns, including in
a PRIMARY KEY or UNIQUE constraint. To create an index on computed columns, you must set the following session options as shown:
If any of these six SET options were not in
effect when you created the table, you get the following message when
you try to create an index on the computed column:
Server: Msg 1934, Level 16, State 1, Line 2
CREATE INDEX failed because the following SET options
have incorrect settings: '<OPTION NAME>'.
In addition, the functions in the computed column must be deterministic. A deterministic function is one that returns the same result every time it is called with the same set of input parameters.
When you create a clustered index on a computed
column, it is no longer a virtual column in the table. The computed
value for the column is stored in the data rows of the table. If you
create a nonclustered index on a computed column, the computed value is
stored in the nonclustered index rows but not in the data rows, unless
you also have a clustered index on the computed column.
Be aware of the overhead involved with indexes on
computed columns. Updates to the columns that the computed columns are
based on result in updates to the index on the computed column as well.
Indexes on computed columns can be useful when you
need an index on large character fields. As discussed earlier, the
smaller an index, the more efficient it is. You could create a computed
column on the large character field by using the CHECKSUM() function. CHECKSUM()
generates a 4-byte integer that is relatively unique for character
strings but not absolutely unique. (Different character strings can
generate the same checksum, so when searching against the checksum, you
need to include the character string as an additional search argument to
ensure that you are matching the right row.) The benefit is that you
can create an index on the 4-byte integer generated by the CHECKSUM()
that can be used to search against the character string instead of
having to create an index on the large character column itself. Listing 1 shows an example of applying this solution.
Listing 1. Using an Index on a Computed Checksum Column
--The first statement is used to disable any previously created
--DDL triggers in the database which would prevent creating a new constraint.
DISABLE TRIGGER ALL ON DATABASE
go
-- First add the computed column to the table
alter table titles add title_checksum as CHECKSUM(title)
go
-- Next, create an index on the computed column
create index NC_titles_titlechecksum on titles(title_checksum)
go
-- In your queries, include both the checksum column and the title column in
-- your search argument
select title_id, ytd_sales
from titles
where title_checksum = checksum('Fifty Years in Buckingham Palace Kitchens')
and title = 'Fifty Years in Buckingham Palace Kitchens'
|
SQL
Server 2008 also supports persisted computed columns. With persisted
computed columns, SQL Server stores the computed values in the table
without requiring an index on the computed column. Like indexed computed
columns, persisted computed columns are updated when any other columns
on which the computed column depends are updated.
Persisted computed columns allow you to create an
index on a computed column that is defined with a deterministic, but
imprecise, expression. This option enables you to create an index on a
computed column when SQL Server cannot determine with certainty whether a
function that returns a computed column expression—for example, a CLR
function that is created in the Microsoft .NET Framework—is both
deterministic and precise.