The CREATE INDEX statement is optimized like any other query. To save on I/O operations, the query processor may choose to scan another index instead of performing a table scan. The sort operation may be eliminated in some situations. On multiprocessor computers with SQL Server 2005 Enterprise Edition, CREATE INDEX can use more processors to perform the scan and sort operations associated with creating the index, in the same way as other queries do. For more information, see Configuring Parallel Index Operations.
The create index operation can be minimally logged if the database recovery model is set to either bulk-logged or simple. For more information, see Choosing a Recovery Model for Index Operations.
Indexes can be created on a temporary table. When the table is dropped or the session ends, the indexes are dropped.
Indexes support extended properties. For more information, see Using Extended Properties on Database Objects.
Clustered Indexes
Creating a clustered index on a table (heap) or dropping and re-creating an existing clustered index requires additional workspace to be available in the database to accommodate data sorting and a temporary copy of the original table or existing clustered index data. For more information, see Determining Index Disk Space Requirements. For more information about clustered indexes, see Creating Clustered Indexes.
Unique Indexes
When a unique index exists, the Database Engine checks for duplicate values each time data is added by a insert operations. Insert operations that would generate duplicate key values are rolled back, and the Database Engine displays an error message. This is true even if the insert operation changes many rows but causes only one duplicate. If an attempt is made to enter data for which there is a unique index and the IGNORE_DUP_KEY clause is set to ON, only the rows violating the UNIQUE index fail. For more information about unique indexes, see Creating Unique Indexes.
Partitioned Indexes
Partitioned indexes are created and maintained in a similar manner to partitioned tables, but like ordinary indexes, they are handled as separate database objects. You can have a partitioned index on a table that is not partitioned, and you can have a nonpartitioned index on a table that is partitioned.
If you are creating an index on a partitioned table, and do not specify a filegroup on which to place the index, the index is partitioned in the same manner as the underlying table. This is because indexes, by default, are placed on the same filegroups as their underlying tables, and for a partitioned table in the same partition scheme that uses the same partitioning columns.
When partitioning a nonunique, clustered index, the Database Engine by default adds any partitioning columns to the list of clustered index keys, if not already specified.
Indexed views can be created on partitioned tables in the same manner as indexes on tables. For more information about partitioned indexes, see Partitioned Tables and Indexes.
Indexed Views
Creating a unique clustered index on a view improves query performance because the view is stored in the database in the same way a table with a clustered index is stored. The query optimizer may use indexed views to speed up the query execution. The view does not have to be referenced in the query for the optimizer to consider that view for a substitution.
The following steps are required to create an indexed view are critical to the successful implementation of the view:
-
Verify the SET options are correct for all existing tables that will be referenced in the view.
-
Verify the SET options for the session are set correctly before creating any new tables and the view.
-
Verify the view definition is deterministic.
-
Create the view by using the WITH SCHEMABINDING option.
-
Create the unique clustered index on the view.
Required SET Options for Indexed Views
Evaluating the same expression can produce different results in the Database Engine if different SET options are active when the query is executed. For example, after the SET option CONCAT_NULL_YIELDS_NULL is set to ON, the expression 'abc' + NULL returns the value NULL. However, after CONCAT_NULL_YIEDS_NULL is set to OFF, the same expression produces 'abc'.
To make sure that the views can be maintained correctly and return consistent results, indexed views require fixed values for several SET options. The SET options in the following table must be set to the values shown in the Required Value column whenever the following conditions occur:
-
The indexed view is created.
-
There is any insert, update, or delete operation performed on any table that participates in the indexed view. This includes operations such as bulk copy, replication, and distributed queries.
-
The indexed view is used by the query optimizer to produce the query plan.
|
SET options
|
Required value
|
Default server value
|
Default
OLE DB and ODBC value
|
Default
DB-Library value
|
|---|
|
ANSI_NULLS
|
ON
|
ON
|
ON
|
OFF
|
|
ANSI_PADDING
|
ON
|
ON
|
ON
|
OFF
|
|
ANSI_WARNINGS*
|
ON
|
ON
|
ON
|
OFF
|
|
ARITHABORT
|
ON
|
ON
|
OFF
|
OFF
|
|
CONCAT_NULL_YIELDS_NULL
|
ON
|
ON
|
ON
|
OFF
|
|
NUMERIC_ROUNDABORT
|
OFF
|
OFF
|
OFF
|
OFF
|
|
QUOTED_IDENTIFIER
|
ON
|
ON
|
ON
|
OFF
|
*In SQL Server 2005, setting ANSI_WARNINGS to ON implicitly sets ARITHABORT to ON when the database compatibility level is set to 90. If the database compatibility level is set to 80 or earlier, the ARITHABORT option must explicitly be set to ON.
If you are using an OLE DB or ODBC server connection, the only value that must be modified is the ARITHABORT setting. All DB-Library values must be set correctly either at the server level by using sp_configure or from the application by using the SET command. For more information about SET options, see Using Options in SQL Server.
Important: |
|---|
|
We strongly recommend that the ARITHABORT user option be set server-wide to ON as soon as the first indexed view or index on a computed column is created in any database on the server.
|
Deterministic Functions
The definition of an indexed view must be deterministic. A view is deterministic if all expressions in the select list, as well as the WHERE and GROUP BY clauses, are deterministic. Deterministic expressions always return the same result any time they are evaluated with a specific set of input values. Only deterministic functions can participate in deterministic expressions. For example, the DATEADD function is deterministic because it always returns the same result for any given set of argument values for its three parameters. GETDATE is not deterministic because it is always invoked with the same argument, but the value it returns changes each time it is executed. For more information, see Deterministic and Nondeterministic Functions.
Even if an expression is deterministic, if it contains float expressions, the exact result may depend on the processor architecture or version of microcode. To ensure data integrity, such expressions can participate only as nonkey columns of indexed views. Deterministic expressions that do not contain float expressions are called precise. Only precise deterministic expressions can participate in key columns and in WHERE or GROUP BY clauses of indexed views.
Use the IsDeterministic property of the COLUMNPROPERTY function to determine whether a view column is deterministic. Use the IsPrecise property of the COLUMNPROPERTY function to determine if a deterministic column in a view with schema binding is precise. COLUMNPROPERTY returns 1 if TRUE, 0 if FALSE, and NULL for input that is not valid. This means the column is not deterministic or not precise.
Additional Requirements
In addition to the SET options and deterministic function requirements, the following requirements must be met:
-
The user that executes CREATE INDEX must be the owner of the view.
-
If the view definition contains a GROUP BY clause, the key of the unique clustered index can reference only the columns specified in the GROUP BY clause.
-
Base tables must have the correct SET options set at the time the table is created or it cannot be referenced by the view with schema binding.
-
Tables must be referenced by two-part names, schema.tablename, in the view definition.
-
User-defined functions must be created by using the WITH SCHEMABINDING option.
-
User-defined functions must be referenced by two-part names, schema.function.
-
The view must be created by using the WITH SCHEMABINDING option.
-
The view must reference only base tables in the same database, not other views.
-
The view definition must not contain the following:
|
COUNT(*)
|
ROWSET function
|
|
Derived table
|
self-join
|
|
DISTINCT
|
STDEV, VARIANCE, AVG
|
|
float*, text, ntext, or image columns
|
Subquery
|
|
full-text predicates (CONTAIN, FREETEXT)
|
SUM on nullable expression
|
|
CLR user-defined aggregate function
|
TOP
|
|
MIN, MAX
|
UNION
|
*The indexed view can contain float columns; however, such columns cannot be included in the clustered index key.
If GROUP BY is present, the VIEW definition must contain COUNT_BIG(*) and must not contain HAVING. These GROUP BY restrictions are applicable only to the indexed view definition. A query can use an indexed view in its execution plan even if it does not satisfy these GROUP BY restrictions.
Indexed views can be created on a partitioned table, and can themselves be partitioned. For more information about partitioning, see the previous section "Partitioned Indexes".
To prevent the Database Engine from using indexed views, include the OPTION (EXPAND VIEWS) hint on the query. Also, if any of the listed options are incorrectly set, this will prevent the optimizer from using the indexes on the views. For more information about the OPTION (EXPAND VIEWS) hint, see SELECT (Transact-SQL).
The compatibility level of the database cannot be less than 80. A database containing an indexed view cannot be changed to a compatibility level lower than 80.
XML Indexes
Index Key Size
The maximum size for an index key is 900 bytes. Indexes on varchar columns that exceed 900 bytes can be created if the existing data in the columns do not exceed 900 bytes at the time the index is created; however, subsequent insert or update actions on the columns that cause the total size to be greater than 900 bytes will fail. For more information, see Maximum Size of Index Keys. The index key of a clustered index cannot contain varchar columns that have existing data in the ROW_OVERFLOW_DATA allocation unit. If a clustered index is created on a varchar column and the existing data is in the IN_ROW_DATA allocation unit, subsequent insert or update actions on the column that would push the data off-row will fail. For more information about allocation units, see Table and Index Organization.
In SQL Server 2005, nonclustered indexes can include nonkey columns in the leaf level of the index. These columns are not considered by the Database Engine when calculating the index key size . For more information, see Index with Included Columns.
Computed Columns
Indexes can be created on computed columns. In SQL Server 2005, computed columns can have the property PERSISTED. This means that the Database Engine stores the computed values in the table, and updates them when any other columns on which the computed column depends are updated. The Database Engine uses these persisted values when it creates an index on the column, and when the index is referenced in a query.
To index a computed column, the computed column must deterministic and precise. However, using the PERSISTED property expands the type of indexable computed columns to include:
-
Computed columns based on Transact-SQL and CLR functions and CLR user-defined type methods that are marked deterministic by the user.
-
Computed columns based on expressions that are deterministic as defined by the Database Engine but imprecise.
Persisted computed columns require the following SET options to be set as shown in the previous section "Required SET Options for Indexed Views".
The UNIQUE or PRIMARY KEY constraint can contain a computed column as long as it satisfies all conditions for indexing. Specifically, the computed column must be deterministic and precise or deterministic and persisted. For more information about determinism, see Deterministic and Nondeterministic Functions.
Computed columns derived from image, ntext, text, varchar(max), nvarchar(max), varbinary(max), and xml data types can be indexed either as a key or included nonkey column as long as the computed column data type is allowable as an index key column or nonkey column. For example, you cannot create a primary XML index on a computed xml column. If the index key size exceeds 900 bytes, a warning message is displayed.
Creating an index on a computed column may cause the failure of an insert or update operation that previously worked. Such a failure may take place when the computed column results in arithmetic error. For example, in the following table, although computed column c results in an arithmetic error, the INSERT statement works.
CREATE TABLE t1 (a int, b int, c AS a/b);
INSERT INTO t1 VALUES (1, 0);
If, instead, after creating the table, you create an index on computed column c, the same INSERT statement will now fail.
CREATE TABLE t1 (a int, b int, c AS a/b);
CREATE UNIQUE CLUSTERED INDEX Idx1 ON t1(c);
INSERT INTO t1 VALUES (1, 0);
For more information, see Creating Indexes on Computed Columns.
Included Columns in Indexes
Nonkey columns, called included columns, can be added to the leaf level of a nonclustered index to improve query performance by covering the query. That is, all columns referenced in the query are included in the index as either key or nonkey columns. This allows the query optimizer to locate all the required information from an index scan; the table or clustered index data is not accessed. For more information, see Index with Included Columns.
Specifying Index Options
SQL Server 2005 introduces new index options and also modifies the way in which options are specified. In backward compatible syntax, WITH option_name is equivalent to WITH ( <option_name> = ON ). When you set index options, the following rules apply:
-
New index options can only be specified by using WITH (option_name = ON | OFF).
-
Options cannot be specified by using both the backward compatible and new syntax in the same statement. For example, specifying WITH (DROP_EXISTING, ONLINE = ON) causes the statement to fail.
-
When you create an XML index, the options must be specified by using WITH (option_name = ON | OFF).
DROP_EXISTING Clause
You can use the DROP_EXISTING clause to rebuild the index, add or drop columns, modify options, modify column sort order, or change the partition scheme or filegroup.
If the index enforces a PRIMARY KEY or UNIQUE constraint and the index definition is not altered in any way, the index is dropped and re-created preserving the existing constraint. However, if the index definition is altered the statement fails. To change the definition of a PRIMARY KEY or UNIQUE constraint, drop the constraint and add a constraint with the new definition.
DROP_EXISTING enhances performance when you re-create a clustered index, with either the same or different set of keys, on a table that also has nonclustered indexes. DROP_EXISTING replaces the execution of a DROP INDEX statement on the old clustered index followed by the execution of a CREATE INDEX statement for the new clustered index. The nonclustered indexes are rebuilt once, and then only if the index definition has changed. The DROP_EXISTING clause does not rebuild the nonclustered indexes when the index definition has the same index name, key and partition columns, uniqueness attribute, and sort order as the original index.
Whether the nonclustered indexes are rebuilt or not, they always remain in their original filegroups or partition schemes and use the original partition functions. If a clustered index is rebuilt to a different filegroup or partition scheme, the nonclustered indexes are not moved to coincide with the new location of the clustered index. Therefore, even the nonclustered indexes previously aligned with the clustered index, they may no longer be aligned with it. For more information about partitioned index alignment, see Special Guidelines for Partitioned Indexes.
The DROP_EXISTING clause will not sort the data again if the same index key columns are used in the same order and with the same ascending or descending order, unless the index statement specifies a nonclustered index and the ONLINE option is set to OFF. If the clustered index is disabled, the CREATE INDEX WITH DROP_EXISTING operation must be performed with ONLINE set to OFF. If a nonclustered index is disabled and is not associated with a disabled clustered index, the CREATE INDEX WITH DROP_EXISTING operation can be performed with ONLINE set to OFF or ON.
When indexes with 128 extents or more are dropped or rebuilt, the Database Engine defers the actual page deallocations, and their associated locks, until after the transaction commits. For more information, see Dropping and Rebuilding Large Objects.
ONLINE Option
The following guidelines apply for performing index operations online:
-
The underlying table cannot be altered, truncated, or dropped while an online index operation is in process.
-
Additional temporary disk space is required during the index operation. For more information, see Determining Index Disk Space Requirements.
-
Online operations can be performed on partitioned indexes and indexes that contain persisted computed columns, or included columns.
For more information, see Performing Index Operations Online.
Row and Page Locks Options
When ALLOW_ROW_LOCKS = ON and ALLOW_PAGE_LOCK = ON, row-, page-, and table-level locks are allowed when accessing the index. The Database Engine chooses the appropriate lock and can escalate the lock from a row or page lock to a table lock. For more information, see Lock Escalation (Database Engine).
When ALLOW_ROW_LOCKS = OFF and ALLOW_PAGE_LOCK = OFF, only a table-level lock is allowed when accessing the index.
For more information about configuring the locking granularity for an index, see Customizing Locking for an Index.
Viewing Index Information
To return information about indexes, you can use catalog views, system functions, and system stored procedures. For more information, see Viewing Index Information.