Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
1 of 13
Sign in
home
articles
quick answers
discussions
features
community
help
CPOL
Rate this:
Introduction
Before a couple of weeks one friend of mine told me, he had a problem with poor database performance. He asked me how to find what
cause poor performance and how to fix this problem. I have some knowledge about database tuning and I advised him some
recommendations. After some time I had the same problem with poor performance and It was important to fix this problem very soon.
After this situation I realized that it would be a great to have same guide so I have decided to write o some article about that.
In this first article about database performance tuning I will describe some techniques about index tuning.
At the beginning is important that you understand indexes. SQL Server 2005 and 2008 supports two types of indexes for most data
types: clustered and non-clustered. It also supports full-text indexes and XML indexes, but those types of indexes are relevant only for
specific data types.
Basic terms
I think is important to shortly describe some basic terms before we will start discuss about indexing strategies.
Non-Clustered Indexes
6/11/2015 1:05 AM
2 of 13
The data is present in random order, but the logical ordering is specified by the index. The data rows may be randomly spread
throughout the table. The non-clustered index tree contains the index keys in sorted order, with the leaf level of the index containing the
pointer to the page and the row number in the data page. In non-clustered index:
The physical order of the rows is not the same as the index order.
Typically created on column used in JOIN, WHERE, and ORDER BY clauses.
Good for tables whose values may be modified frequently.
Microsoft SQL Server creates non-clustered indices by default when CREATE INDEX command is given. There can be more than one
non-clustered index on a database table. There can be as many as 249 non-clustered indexes per table in SQL Server 2005 and 999
non-clustered indexes per table in SQL Server 2008. It is appropriate to create non-clustered index on columns which are:
Frequently used in the search criteria.
Used to join other tables.
Used as foreign key fields.
Of having high selectivity (column which returns a low percentage (0-5%) of rows from a total number of rows on a particular
value)
Used in the ORDER BY clause.
Of type XML (primary and secondary indexes need to be created; more on this in the coming articles).
Clustered Indexes
Clustering alters the data block into a certain distinct order to match the index, resulting in the row data being stored in order. Therefore,
only one clustered index can be created on a given database table. Clustered indices can greatly increase overall speed of retrieval, but
usually only where the data is accessed sequentially in the same or reverse order of the clustered index, or when a range of items is
selected.
Since the physical records are in this sort order on disk, the next row item in the sequence is immediately before or after the last one, and
so fewer data block reads are required. The primary feature of a clustered index is therefore the ordering of the physical data rows in
accordance with the index blocks that point to them. Some databases separate the data and index blocks into separate files, others put
two completely different data blocks within the same physical file(s). Create an object where the physical order of rows is same as the
index order of the rows and the bottom(leaf) level of clustered index contains the actual data rows.
Many developers tent to think that SQL Server stores data according to the order the records were entered into the table. This is not true.
SQL Server stores data according to the way you create a clustered index. Keep in mind that SQL Server enforces PRIMARY KEY constraint
by placing unique index on table. If there is no other clustered index on table, SQL Server will make PRIMARY KEY index cluster. When
creating indexes other that PRIMARY KEY or UNIQUE KEY indexes, by default SQL Server will create them as non-clustered.
It is very important to have a clustered index on every table. If table does not have a clustered index, than all new records have to be
added to the last data page occupied by the table. If table has a clustered index, than new records can be added to the last page or in the
middle of the table. They can be added to the more suitable position according to he clustered index.
Covering Indexes
You can extend functionality of non-clustered indexes by including non-key columns to the leaf level of the non-clustered index. By
including non-key columns, you can create non-clustered indexes that cover more queries. This indexes are called Covering indexes or
Indexes with included columns. The notion of covering indexes is that SQL Server doesnt need to user lookups between the non-clustered
index and the table to return query results. Because a clustered index is the actual table, clustered index always cover queries. Included
non-key columns have the following benefits:
They can be data types not allowed as index key columns.
They are not considered by the Database Engine when calculating the number of index key columns or index key size.
A covering indexes always perform better than a non-covering indexes.
When you are creating covering index you should keep in mind some guidelines:
Non-key columns are defined in the INCLUDE clause of the CREATE INDEX statement.
Non-key columns can only be defined on non-clustered indexes on tables or indexed views.
All data types are allowed except text, ntext, and image.
Computed columns that are deterministic and either precise or imprecise can be included columns.
As with key columns, computed columns derived from image, ntext, and text data types can be non-key (included) columns as
long as the computed column data type is allowed as a non-key index column.
Column names cannot be specified in both the INCLUDE list and in the key column list.
Column names cannot be repeated in the INCLUDE list.
A maximum of 1023 additional columns can be used as non-key columns (a table can have a maximum of 1024 columns).
Performance benefit gained by using covering indexes is typically great for queries that return a large number of rows (by the way this
queries are called a non-selective queries). For queries that return only a small number of rows performance is small. But here you can ask,
what is the small number of rows? Small numer of rows could be 10 rows for table with hundreds of rows or 1000 rows for table with 1
000 000 rows.
Filtered Indexes
6/11/2015 1:05 AM
3 of 13
With SQL Server 2008 comes new type of index called Filtered Index. Filtered Index is a non-clustered index, especially suited to cover
subset of data determined by simple WHERE clause. The B-tree containing rows for filtered index will contain only rows which satisfy the
filter criteria used while creating index and hence well designed Filtered Index can rapidly improve query performance, reduce index
maintenance costs and rapidly reduce index storage costs. Filtered index offers some benefits over standard full non-clustered index:
As discussed above, the filtered index contains only those rows which satisfy the defined filter criteria. As a result it reduces the
storage space requirement for the index. In the example below I will explain it more.
The filtered statistics or statistics for a filtered index are more compact and accurate, because they consider only the rows in the
filtered index and the smaller size of the filtered index reduces the cost/overhead of updating the statistics.
The impact of data modification is less with a filtered index as it is updated only when the data of the index is impacted or a new
record is inserted matching the filter criteria.
Maintenance costs will be reduced as well since only a subset of rows will be in consideration while re-organizing or rebuilding the
index.
And most important, as it is an optimized non-clustered index, the query performance will improve if only a subset of data, which
is covered by the filtered index criteria, is required.
In previous versions of SQL Server to get a similar benefit you had an option to use indexed vies. Using indexed views looks similar to
filtered indexes but you can find some differences between this tho approaches. Here is a table with some of them:
Expressions
Filtered Indexes
Indexes Views
Non-Unique or Unique
Computed Columns
Joins
Are supported.
Fill Factor
The fill factor option is provided for tuning index data storage and performance. The fill-factor value determines the percentage of space
on each leaf-level page to be filled with data, reserving the remainder on each page as free space for future growth. For example,
specifying a fill-factor value of 80 means that 20 percent of each leaf-level page will be left empty, providing space for index expansion as
data is added to the underlying table. The empty space is reserved between the index rows rather than at the end of the index. The
fill-factor value is a percentage from 1 to 100, and the server-wide default is 0 which means that the leaf-level pages are filled to capacity.
Fill-factor values 0 and 100 are the same in all respects.
The fill-factor setting applies only when the index is created, or rebuilt. The SQL Server Database Engine does not dynamically keep the
specified percentage of empty space in the pages. Trying to maintain the extra space on the data pages would defeat the purpose of fill
factor because the Database Engine would have to perform page splits to maintain the percentage of free space specified by the fill factor
on each page as data is entered. Here are some information you should take into consideration when you modifying fill factor:
Depending on how the data is inserted, updated and deleted in the table dictates how full the leaf level pages should be in the
table. To fine tune this setting typically takes some testing and analysis. This could be critical for large active tables in your
database.
If data is always inserted at the end of the table, then the fill factor could be between 90 to 100 percent since the data will never be
inserted into the middle of a page. UPDATE and DELETE statements may expand (UPDATE) or decrease (DELETE) the space needed
for each leaf level page. This should be fine tuned based on testing.
If the data can be inserted anywhere in the table then a fill factor of 60 to 80 percent could be appropriate based on the INSERT,
UPDATE and DELETE activity. However, it is necessary to conduct some testing and analysis to determine the appropriate settings
for your environment.
With all things being equal i.e. table size, SQL Server versions, options, etc., the lower the fill factor percentage the more storage
that could be needed as compared to a higher fill factor where the pages are more compact.
Another aspect to take into consideration is your index rebuild schedule. If you cannot rebuild your indexes on a regular schedule
and if you have a high level of INSERT, UPDATE and DELETE activity throughout the table, one consideration may be to have a
lower fill factor to limit the fragmentation. The trade-off may be that more storage is needed.
6/11/2015 1:05 AM
4 of 13
Examples
Here I will show you some basic examples which demonstrate how indexes can affect performance of queries. For test purposes I have
created table [Person].[Person_Test] in database AdwentureWorks2008R2. This table has the same structure as [Person].[Person]. I have
created this table because I don't want to change existing table.
6/11/2015 1:05 AM
5 of 13
6/11/2015 1:05 AM
6 of 13
6/11/2015 1:05 AM
7 of 13
6/11/2015 1:05 AM
8 of 13
6/11/2015 1:05 AM
9 of 13
You can see that Estimated Subtree Cost is 0.0380656. But what will happen if we use Order By clause? Lets try to investigate.
6/11/2015 1:05 AM
10 of 13
When we user Order By clause SQL Server will sort requested data. As you can see, the sort operation is the most resource sensitive
operation in this case and the overall Estimated Subtree cost is increased. To improve this query's performance we can create a
non-clustered index on OrderDate column.
Hide Copy Code
But here you can ask what if you need data in descending order. You can apply the same technique for indexes using descending order. I
will show you that they can affect performance on the same way as indexes using ascending order.
6/11/2015 1:05 AM
11 of 13
When you run query which sorts records using descending option you can see that Estimated Subtree Cost is the same as in case of
ascending order without index. For increasing performance of query you can create non-clustered index using descending option:
Hide Copy Code
History
7 August 2011 - Original version posted.
9 August 2011 - Filtered Indexes chapter updated.
License
This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)
Share
EMAIL
6/11/2015 1:05 AM
12 of 13
Optimizing Performance in
NHibernate: Part 2: A Collection of
Enhancements
Search Comments
Profile popups
Spacing Relaxed
Layout Normal
Per page 25
Update
6/11/2015 1:05 AM
13 of 13
Thumbs up
Amit Dhakre
28-Oct-15 3:57
Member 11972038
9-Sep-15 10:41
Now I understand
Misha Yundt
30-Jul-15 12:33
great article!
Member 10929609
7-Jul-14 3:58
Member 10707386
28-Mar-14 9:05
My vote of 5
drothe
7-Jan-14 10:25
Kanasz Robert
7-Jan-14 22:35
Re: My vote of 5
My vote of 5
Prasad Khandekar
6-Jun-13 21:01
My vote of 5
Savalia Manoj M
3-Jun-13 20:00
Kanasz Robert
3-Jun-13 21:25
Re: My vote of 5
My vote of 5
Re: My vote of 5
My vote of 5
Re: My vote of 5
Re: My vote of 5
Good Article
Re: Good Article
My vote of 5
21-Apr-13 22:00
GregoryW
21-Mar-13 3:55
Kanasz Robert
21-Mar-13 4:02
GregoryW
21-Mar-13 4:08
xmaster123_2
13-Mar-13 0:57
Kanasz Robert
13-Mar-13 4:16
5-Mar-13 5:20
5-Mar-13 22:27
Dave Kerr
News
Kanasz Robert
Kanasz Robert
Great Article
General
21-Apr-13 21:42
VitorHugoGarcia
Re: My vote of 5
TechnoGeek001
7-Dec-12 5:56
Kanasz Robert
12-Jan-13 23:13
strucker_luc
18-Nov-12 4:15
Kanasz Robert
18-Nov-12 4:21
pip010
7-Nov-12 13:05
Kanasz Robert
Suggestion
Question
8-Nov-12 0:12
Refresh
Bug
Answer
Joke
Praise
1 2 3 4 Next
Rant
Admin
Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.
Permalink | Advertise | Privacy | Terms of Use | Mobile
Web01 | 2.8.151103.1 | Last Updated 20 Aug 2011
Select Language
Layout: fixed |
fluid
6/11/2015 1:05 AM