SQL Query Performance - Functions and Indexes

Indexes play an important role in SQL query performance, but improper knowledge of how indexes work can lead to degraded performance. In this article I will throw some light on one such practices. We all know that indexes help in select statements and make other statements (insert, update, delete) slower. At the same time if we use a function on an indexed column in a where statement then it does not use the index and hence the query performs the same as when it does not have a index. Let's look ar a realistic example.

Step 1: Create a table Person 

  1. CREATE TABLE [dbo].[Person](  
  2. [ID] [char](800) NULL,  
  3. [FirstName] [char](2000) NULL,  
  4. [LastName] [char](3000) NULL,  
  5. [City] [char](500) NULL  
  6. )  
Step 2: Insert some random data
  1. INSERT INTO Person (ID,FirstName,LastName,City)  
  2. SELECT TOP 1000 ROW_NUMBER() OVER (ORDER BY a.name) RowID,  
  3. ‘Vineet’,  
  4. CASE WHEN ROW_NUMBER() OVER (ORDER BY a.name)%2 = 1 THEN ‘Sanjay’  
  5. ELSE ‘Mahesh’ END,  
  6. CASE WHEN ROW_NUMBER() OVER (ORDER BY a.name)%10 = 1 THEN ‘New Delhi’  
  7. WHEN ROW_NUMBER() OVER (ORDER BY a.name)%10 = 5 THEN ‘Chennai’  
  8. WHEN ROW_NUMBER() OVER (ORDER BY a.name)%10 = 3 THEN ‘Hyderabad’  
  9. ELSE ‘Bangalore’ END  
  10. FROM sys.all_objects a  
  11. CROSS JOIN sys.all_objects b  
  12. GO  
Step 3: Execute a select statement with a where clause on City:
  1. SELECT * FROM Person  
  2. WHERE City = ‘Chennai’  
Note : Until now we do not have any index on the City column.

The following is the execution plan:



Look at the query execution plan, SQL Server did a table scan and that is expected because there is no index on the City column.

Step 4: Create a non-clustered index on the City column as in the following:
  1. CREATE NONCLUSTERED INDEX Index_Person_City  
  2. ON Person (City);  
Step 5: Execute the following select statement:
  1. SELECT * FROM Person  
  2. WHERE City = ‘Chennai’  
Notice the execution plan (below), now SQL Server is using an indexed seek.



Step 6: Now let's execute a select query that uses a function on the column name in the where clause/
  1. SELECT * FROM Person  
  2. WHERE CONVERT(Varchar(500), City) = ‘CHENNAI’  
The following is the Query Execution Plan. SQL Server is using a scan that contributes to 29% of the total cost of the query whereas in Step 5, it used a seek that contributed to only 5% of the total cost.



Conclusion

So in summary, the preceding procedure shows that SQL Server was able to do a seek operation on the City column but when a function is used on the column it was not able to do a seek and hence it performed a scan operation.