DBA,  Performance

Performance Tuning Steps a Query by looking an execution plan and effectiveness of the index creation Part-1

Advertisements

The index is very important and powerful object in the database. It is an optional and secondary object for the table. It will speed up the data return time by navigating the B-tree structure, like a book’s index.

In General, index tuning is important one, putting a right index will speed up the code.

 Please read this post for finding symptoms, where you have issue at server or database or query level.  Most of the time, the query will be the issue. Once, you have long running query start tuning it.

In this post, I am going to share the usage and effectiveness of index from low level to high level.

There are many application code tuning, which I saw no index created and bad index chosen etc. Why that is the case, since the application developers are not native t- SQL coders and they have limited knowledge that RDBMS has engine and an optimizer etc.

In general the index deigns is handled by application team. But, there are times that no supports from the application and DBA needs to look at the index creation. Use Whoisactive or server side trace and capture the long running query and most of the time the missing index or larger heap table will be the issue. For those cases we can take a control and can create an index.

I am going to show some example to creating an index for a query.

The common terminology we use in the tuning:

============

Predicates – Means where clause & join columns. The predicates is the one needs to be indexed.

select ID from Tbl_Index_Tuning where ID =100

Leading column – First columns of the index from left to right. – ID

Create index ix_Tbl_Index_Tuning_ID_Name_Create_Date on Tbl_Index_Tuning (ID,Name,Create_Date).

Select list – It just a select columns of the query. It should always go to the include of the index.

select * from Tbl_Index_Tuning

Composite Index – index with more than one column.

Create index ix_Tbl_Index_Tuning_ID_Name_Create_Date on Tbl_Index_Tuning (ID,Name,Create_Date).

Covering Index – It is a index will have all the columns of the query in the index or include clasue.

Create index ix_Tbl_Index_Tuning_ID_include on Tbl_Index_Tuning (ID) Include (Name,Create_Date)

Equality – (=) where column1 = ‘a’

select ID from Tbl_Index_Tuning where ID =100

Inequality – (<,>, <>) where column1 <> ‘a’

select ID from Tbl_Index_Tuning where ID >100

Selectivity – High unique value, if we have a bad selectivity the index will not be used effectively.

SELECT COUNT(DISTINCT(id))/COUNT(*)FROM[dbo].Tbl_Index_Tuning

SARG method – Search Argument (Minimize using function, implicit conversion, like ‘%a’ etc)

select ID from Tbl_Index_Tuning where Name like ‘sys%’

============

Before creating an index the parameters we look.

Missing index – I use Whoisactive or server side trace to get the poorly performing query and will create and index. We can also use DMV and Tuning advisor to find missing index.

--create database index_Test
--drop database index_Test
select @@version
--Microsoft SQL Server 2012 (SP4) (KB4018073) - 11.0.7001.0 (X64)

-- Enable this to see the difference of logical and physical reads and Execution Times
SET STATISTICS IO ON
SET STATISTICS TIME ON

SET STATISTICS IO OFF
SET STATISTICS TIME OFF

use index_Test

CREATE TABLE Tbl_Index_Tuning (
ID INT identity,
Name VARCHAR (100),
Create_Date DATETIME DEFAULT GETDATE()
); 


insert into Tbl_Index_Tuning (Name,Create_Date)
Select o.name,o.create_date from  sys.objects o , sys.columns c

-- Drop all index

SELECT  'DROP INDEX ' + si.Name + ' ON ' + OBJECT_NAME(object_id)  AS Drop_all_index
FROM  sys.indexes si --join  sys.tables st join si.object_id
WHERE   OBJECT_NAME(object_id) = 'Tbl_Index_Tuning' and si.Name IS NOT null

General guidelines to follow:

How many query involved in the table column (OR) how many times it’s been called, a single index should fulfill more query.

 – In general, the application developer may know how the code and modules are called and which columns are used as a leading column and the combinations of columns etc. It always, good to create a minimal index that should fulfill more queries.

Is the table is heap, does it have a candidate column for clustered index .

– I always try to create a clustered index for larger tables, when we have a right candidate or sometimes, I choose dummy unique columns for VLT. It is always better to have a clustered index. Note that, default the primary key will create clustered index, unless we change to non clustered index.

– Check the leading column that should have a high selectivity.

High selectivity will be good that index will be useful, there are cases we use a low selectivity in the combinations.  – Ex: Where emp_id =10 and emp_name =’mike’ – good empid or sometimes, we do not have good candidate.

Formula to find high selectivity:

SELECT COUNT(DISTINCT(emp_id))/COUNT(*)FROM[dbo].Tbl_Index_Tuning

 

– Remove Lookups by including that column as covering index.

Create index ix_Tbl_Index_Tuning_ID on Tbl_Index_Tuning (ID)

–Drop index ix_Tbl_Index_Tuning_ID on Tbl_Index_Tuning

select * from Tbl_Index_Tuning WHERE ID = 100

 

By creating covering index with include clause will remove the lookup, since all the data is available in the index.

— create index only to ID and include Name & Create_Date and check

Create index ix_Tbl_Index_Tuning_ID_include on Tbl_Index_Tuning (ID) Include (Name,Create_Date)

–Drop index ix_Tbl_Index_Tuning_ID_include on Tbl_Index_Tuning

select * from Tbl_Index_Tuning WHERE ID = 100 –AND Name = ‘sysxsrvs’ AND Create_Date > ‘2011-02-10 20:16:01.910’

Ex:

Column order and how do we choose index column.

– Creating index for combination of columns in single index for all columns (OR) each column need an index.

It depends on the condition Operators and Expressions, we used in the code. It always better to create a combination of columns – composite index, when we know the underlying query and application.

-- create combination columns composite index for ID, Name & Create_Date and check
Create index ix_Tbl_Index_Tuning_ID_Name_Create_Date on Tbl_Index_Tuning (ID,Name,Create_Date)
drop index ix_Tbl_Index_Tuning_ID_Name_Create_Date on Tbl_Index_Tuning

select * from Tbl_Index_Tuning WHERE ID = 100 AND Name = 'sysxsrvs' AND Create_Date > '2011-02-10 20:16:01.910'
select * from Tbl_Index_Tuning where ID = 100 AND Create_Date > '2011-02-10 20:16:01.910'
select * from Tbl_Index_Tuning WHERE ID = 100 AND Create_Date > '2011-02-10 20:16:01.910'

-- The leading/first column is changed, the index is not used
select * from Tbl_Index_Tuning WHERE Create_Date > '2011-02-10 20:16:01.910'
-- seek is going on, Since AND TRUE if both Boolean expressions are TRUE.
select * from Tbl_Index_Tuning WHERE Create_Date > '2011-02-10 20:16:01.910' and ID = 100 
-- Scan is going on, since OR TRUE if either Boolean expression is TRUE.
select * from Tbl_Index_Tuning WHERE Create_Date > '2011-02-10 20:16:01.910' OR ID = 100 

-- When optimizer thinks to return large portion of data scans it 
select * from Tbl_Index_Tuning WHERE ID > 100 AND Create_Date > '2011-02-10 20:16:01.910'
select top 1 * from Tbl_Index_Tuning WHERE ID > 100 AND Create_Date > '2011-02-10 20:16:01.910'


-- Drop that composite index and try the same above query with single index for each column
drop index ix_Tbl_Index_Tuning_ID_Name_Create_Date on Tbl_Index_Tuning


Create index ix_Tbl_Index_Tuning_ID on Tbl_Index_Tuning (ID)
Create index ix_Tbl_Index_Tuning_Name on Tbl_Index_Tuning (Name)
Create index ix_Tbl_Index_Tuning_Create_Date on Tbl_Index_Tuning (Create_Date)

drop index ix_Tbl_Index_Tuning_ID on Tbl_Index_Tuning
drop index ix_Tbl_Index_Tuning_Name on Tbl_Index_Tuning
drop index ix_Tbl_Index_Tuning_Create_Date on Tbl_Index_Tuning

--The index is not combined and it's using a ID index and going to a lookup to heap table to get a remaining data

select * from Tbl_Index_Tuning WHERE ID = 100 AND Name = 'sysxsrvs' AND Create_Date > '2011-02-10 20:16:01.910'

Column order is more important than anything in the index, it depends on the query.

Ex: Where emp_id = 1 (OR) Where emp_id = 1 and emp_name=’a’ etc.

Main important thing here is the column order in the condition from Left to Right.

The leading column/first column should have high selectivity/ unique value in the index statement. The reason SQL will only have “statistics” of first column, so that the index will be useful to get the data. The statistics is another topic will be covered in this post.

– Constraints and indexes are different and thing we need to look “how Unique” – I see still some are thinking that primary key and clustered index are same and we need a PK to have CI.

Waiting to write next parts.

I’m currently working as a SQL server DBA in one of the top MNC. I’m passionate about SQL Server And I’m specialized in Administration and Performance tuning. I’m an active member of SQL server Central and MSDN forum. I also write articles in SQL server Central. For more Click here

2 Comments

Leave a Reply

%d bloggers like this: