SQL Server Performance Tuning using Filtered Covering Index

SQL Server Performance Tuning using Filtered Covering Index

SQL Server Performance Tuning using Filtered Covering Index takes you through a simple scenario where filtered indexes are helpful to improve the performance of frequently used queries. Before starting, I assume that you know “WHAT” a filtered index is or have a look at here. Filtered indexes are very helpful to cover frequently used queries with the minimized index size and maintenance cost. Lets consider a simple scenario as below:

Note: I am using the database [AdventureWorks2016]

Let’s say we have a query to fetch order details for a specific product (870). The same query has been getting called 8 to 10 times per minute. Now, our job is to improve the query performance:

SELECT SalesOrderID,

               OrderQty,

                UnitPrice

FROM     [Sales].[SalesOrderDetail]

WHERE  OrderQty > 2 AND ProductID = 870;

Analysis:

It’s just a simple query and it’s fetching SalesOrderID, OrderQty and UnitPrice for the Product 870 where OrderQty is greater than N(N is a variable). Before looking into the improvement aspects first we’ll see the execution plan and write down our observations:

Switching off ROW COUNT’s and ON statistics:

SQL Server Performance Tuning using Filtered Covering Index

SQL Server Performance Tuning using Filtered Covering Index

SQL Server Performance Tuning using Filtered Covering Index

Observations:

  1. Total Logical Reads: 39875
  2. Clustered Index Scan is happening with Parallelism
  3. From Tool Tip:
  • Object (Index is being used): PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID
  • Output List (Columns Fetching): SalesOrderID, OrderQty and UnitPrice
  • Predicate (Condition): OrderQty > 2 AND ProductID = 870

Find the Solution for Improvements:

Do we really need an index here?

Ans:

Yes, we need any index as the same query is getting called for 8 to 10 times per minute. Also, we could see high on logical reads.

How to decide the index key columns?

Ans:

Your queries where clause can answer this question.

Predicate is OrderQty > 2 AND ProductID = 870.

Now, it’s clear that we need to choose OrderQty AND ProductID are the key columns of the index.

INDEX (ProductID, OrderQty).

But, as per the business requirement OrderQty is a variable which means its value may get changed from time to time. But, productID is 870 only as our business focus is only on specific product 870. Since ProductID = 870 is constant and the same query is getting used widely, we can apply the same filter on Index:

INDEX (OrderQty)

WHERE ProductID = 870.

We determined the key columns also, applied the required filter on it. Now, we will create an index and see how it works.

Create Index and Test it:

CREATE NONCLUSTERED INDEX Custom_NIX_Sales_SalesOrderDetail_OrderQty_ProductID_870

ON [Sales].[SalesOrderDetail] (OrderQty)

WHERE ProductID = 870;

SQL Server Performance Tuning using Filtered Covering Index

SQL Server Performance Tuning using Filtered Covering Index

Surprising, isn’t it? We’ve created a filtered index that exactly covers the query. But, still it’s doing the clustered index scan. Why it’s not using the index that we have created? Let’s force it to use the index that we’ve created. Then, we’ll come to know why it’s not a proper index:

SQL Server Performance Tuning using Filtered Covering Index

SQL Server Performance Tuning using Filtered Covering Index

SQL Server Performance Tuning using Filtered Covering Index

  • From the above images you can clearly see that why optimizer didn’t choose the newly created index unless you forced it.
  • It’s not being used as it’s not the optimized plan. We can see that it’s creating “WorkTable” a temp table on TempDB.
  • Also, the Key Lookup is happening for the column “UnitPrice” and it’s taking the 97% of cost. For each row filtered in Index Seek a Key Lookup is running for the corresponding UnitPrice.
  • Also, we can see the number of executions in Key Lookup is 11552. You have created an index but still the problem is not resolved yet. How to fix and improve it?

Draw the conclusion:

  • If we can remove the Key Lookup then optimizer surely chose the covering filtered index that we created as a solution.
  • Remove the Key Lookup by including the column “UnitPrice” as below:

CREATE NONCLUSTERED INDEX Custom_NIX_Sales_SalesOrderDetail_OrderQty_ProductID_870

ON [Sales].[SalesOrderDetail](OrderQty)

INCLUDE (UnitPrice)

WHERE ProductID = 870;

Test the Solution:

After adding the included column, you can see the optimizer started using the newly created index:

SQL Server Performance Tuning using Filtered Covering Index

SQL Server Performance Tuning using Filtered Covering Index

 

Now, compare the executions between Clustered Index SCAN and newly created Non-Clustered filtered index seek:

SQL Server Performance Tuning using Filtered Covering Index

SQL Server Performance Tuning using Filtered Covering Index

SQL Server Performance Tuning using Filtered Covering Index

Performance Improvements:

SQL Server Performance Tuning using Filtered Covering Index

We could see the improvement of 97% in CPU and 99% in IO. This is all we are just talking about one execution. If you can calculate the average improvement based on number of executions per a given day, it’ll be huge and you can project the same to your end customer.

Summary:

  • Always chose the right candidate for the right position (Key Column, Filtered Column and Include column).
  • Costly Key lookups are the first thing to be removed from your execution plans.
  • Always consider the data growth percentage in production while designing an index.
  • Filtered indexes are really helpful for more frequent queries based on a constant conditions as it reduces the index storage which in-turns reduces the maintenance.
  • Post SQL Server Performance Tuning using Filtered Covering Index can help you to understand the basics of covering filtered index usage in real time production environment.

 

Posted in Performance Tuning, SQL Development | Tagged | 1 Comment

Clustered Index On UniqueIdentifier Column

Clustered_Index_On_UniqueIdentifier

Hello all,

It’s been a year since we posted a blog. It’s been the busiest year of my life. However, we strongly believe that learning is a journey and it should be a continuing process. Coming to the point, recently I had to handle a customer problem with the overall application performance. Found some interesting problems and thought of sharing the same.   

 

Clustered Index on UNIQUEIDENTIFIER column

 

Problem Statement:

Clustered Index on UNIQUEIDENTIFIER column takes you through high-level problems with the GUID. We have a crucial database environment where we were facing some performance issues. We identified a few issues fixed them. While analyzing the overall database architecture, we observed a few interesting facts which are highly impacting the database performance. One of the major observations is having a clustered index on UNIQUEIDENTIFIER column on Transactional tables where we are seeing a lot of writes on those tables. When we captured the statistics below are the observations:

1. Index Rebuild is happening on Sunday afternoon

2. Index fragmentation (Index on UNIQUEIDENTIFIER) is reaching 65% by Monday afternoon

3. We do not get any maintenance window during the week as the application is running in 24X7

4. We are using the same fragmented index during the week till Saturday

5. On that clustered index Bad Page Splits Per Second is high > 38% of Batch Requests Per Sec

6. These indexes are being highly used across the application for both WRITES and READS

An expert from the customer side asked us to brief our analysis and the generic information on why clustered index on UNIQUEIDENTIFIER is creating the problem and the possible solutions. Here is our analysis and the solution suggested.

Continue reading

Posted in Database Design, Performance Tuning, SQL Development | Tagged , , , , | 2 Comments

Latest SQL DBA Interview Questions and Answers

Latest SQL DBA Interview Questions and AnswersThe post Latest SQL DBA Interview Questions and Answers takes you through the latest SQL DBA interview experiences shared by blog followers. You can also share your interview experience and we can provide you the answers:

Q. Can we perform a log backup with COPY ONLY option?

Ans:

Yes Of course we can perform Copy Only log backups

Q. What are the marked transactions in SQL Server?

Ans:

When we are dealing with related databases which means there is a dependency between databases and we need to establish a recovery strategy for all databases to the same consistent phase. But with this approach we may lose the recently committed transactions. Marking transaction logs is beneficial when you are dealing with multiple databases and want to restore all of them to the same point in time recovery.

This is used in rare cases and suitable for TFS because when there is disaster ‘occurs we need our data back in all databases to the same consistent manner, if you don’t mark the T-Logs and restore using the normal point in time recovery it might get our data back but with inconsistency between databases. For example I have created a new branch in TFS for new development work and and somebody checking and modifying code this total activities are recorded in multiple databases so when we want to restore it back we should get exactly the same consistent point. Have a look at here:

https://docs.microsoft.com/en-us/sql/relational-databases/backup-restore/use-marked-transactions-to-recover-related-databases-consistently

Q. Why Primary key is mandate for Transaction Replication?

Ans: Continue reading

Posted in Interview Q&A, SQL Server DBA | Tagged , , , , , , | 1 Comment