How to Search and Destroy Non-SARGable Queries on Your Server

Published on: 2017-08-22

Unexpected SQL Server Performance Killers #3

Photo by Cibi Chakravarthi on Unsplash

In this series I explore scenarios that hurt SQL Server performance and show you how to avoid them. Pulled from my collection of “things I didn’t know I was doing wrong for years.”

Watch this post on YouTube.


Looking for a script to find non-SARGable queries on your server? Scroll to the bottom of this post.

What is a “SARGable” query?

Just because you add an index to your table doesn’t mean you get immediate performance improvement. A query running against that table needs to be written in such a way that it actually takes advantage of that index.

SARGable, or “Search Argument-able”, queries therefore are queries that are capable of utilizing indexes.

Examples please!

Okay let’s see some examples of SARGable and non-SARGable queries using my favorite beverage data.

There are non-clustered indexes on the Name and CreateDate columns

First, let’s look at a non-SARGable query:

Although this query correctly filters our rows to a specific date, it does so with this lousy execution plan:

SQL Server has to perform an Index Scan, or in other words has to check every single page of this index, to find our ‘2017–08–19’ date value.

SQL Server does this because it can’t immediately look at the value in the index and see if it is equal to the ‘2017–08–19’ date we supplied — we told it first to convert every value in our column/index to a CHAR(10) date string so that it can be compared as a string.

Since the SQL Server has to first convert every single date in our column/index to a CHAR(10) string, that means it ends up having to read every single page of our index to do so.

The better option here would be to leave the column/index value as a datetime2 datatype and instead convert the right hand of the operand to a datetime2:

Alternatively, SQL Server is smart enough to do this conversion implicitly for us if we just leave our ‘2017–08–19’ date as a string:

In this scenario SQL gives us an Index Seek because it doesn’t have to modify any values in the column/index in order to be able to compare it to the datetime2 value that ‘2017–08–19’ got converted to.

This means SQL only has to read what it needs to output to the results. Much more efficient.

One more example

Based on the last example we can assume that any function, explicit or implicit, that is running on the column side of an operator will result in a query that cannot make use of index seeks, making it non-SARGable.

That means that instead of doing something non-SARGable like this:

We want to make it SARGable by doing this instead:

In short, keep in mind whether SQL Server will have to modify the data in a column/index in order to compare it — if it does, your query probably isn’t SARGable and you are going to end up scanning instead of seeking.

OK, non-SARGable queries are bad…how do I check if I have any on my server?

The script below looks at cached query plans and searches them for any table or index scans. Next, it looks for scalar operators, and if it finds any it means we have ourselves a non-SARGable query. The fix is then to rewrite the query to be SARGable or add a missing index.

 

I’ve found this script useful for myself, but if you find any issues with it please let me know, thanks!

Thanks for reading. You might also enjoy following me on Twitter.

Want to learn even more SQL?

Sign up for my newsletter to receive weekly SQL tips!

How to Eliminate Ugly Nested REPLACE() Functions

Published on: 2017-08-15

SQL in 60 Seconds #4

On white: Who you really are” by James Jordan is licensed under CC BY-ND 2.0

Prefer video? Watch this content on my YouTube channel!

How many times have you had to transform some column value and ended up stacking several nested SQL REPLACE() functions like this?

Ugly right? And that’s after careful formatting to try and make it look readable. I could have just left it as:

Here we only have 4 nested REPLACE functions. My shameful record is 29. I’m not proud of it, but sometimes it’s the only way to get things done.

Not only are these nested REPLACE() functions difficult to write, but they are difficult to read too.

Instead of suffering through all of that ugly nesting, what you can do instead is use CROSS APPLY:

Technically the CROSS APPLY solution uses more characters. But it is infinitely more readable.

And the server? The server doesn’t care about the additional characters —it still compiles it down to the same 1s and 0s:

So next time you have to nest several REPLACE() functions (or any other string functions), do yourself a favor and make it more readable by using CROSS APPLY instead. Your future self will thank you.

Thanks for reading. You might also enjoy following me on Twitter.

Want to learn even more SQL?

Sign up for my newsletter to receive weekly SQL tips!

SQLskills is Giving Away Free Training!

Published on: 2017-08-11

SQLskills is giving away free training for their performance tuning and optimization classes. My entry for the competition is below. If you decide to enter for yourself, entries are due by 11:59 PM Pacific Time on Sunday, August 13th, 2017.

I would love to attend the Immersion Event on Performance Tuning and Optimization — Part 1 training with Paul and Kimberly of SQLskills.

Why do I want to attend?

I want my brain to be filled past the brim with SQL Server internals and performance tuning knowledge. And I know this class will provide that opportunity.

I saw Kimberly present at PASS Summit in 2013. In 75 minutes, I had filled 4 pages of notes about skewed table data and how it affects statistics. I received great information that was immediately applicable to the queries I was working on back at the office.

I’ve never seen Paul present live, but I’ve been responsible for more than a few dozen hits to his blog posts on DBCC IND and DBCC PAGE. Whenever I have a question about SQL Server internals, I inevitably think “does Paul have a blog post on this topic?”

I’ve heard from others that IEPTO1 is amazing (and exhausting…in a good way!). I’ve learned so much from reading SQLskills team’s blog posts, watching Pluralsight, and sitting in at SQL Saturday sessions that I am certain that I would thoroughly enjoy a week of intense training with Paul and Kim.

How would I use the knowledge?

By giving back to the community.

Every week I write blog posts and create videos teaching analysts, developers, and DBAs how to improve their SQL querying skills. I speak at local user groups, SQL Saturdays, and at conferences. I help coworkers and those on Twitter with solving their SQL problems.

By taking this training, I will advance my own technical understanding, which in turn helps me be a better SQL mentor.

My favorite type of performance tuning challenge

I love it when I can decode some of the “magic” that SQL Server is doing behind the scenes.

For example, recently when learning to work with JSON in SQL Server 2016, I was mystified by how SQL Server could quickly filter JSON data using a non-persisted computed column index. Was it truly parsing JSON on the fly or was it doing something else?

That curiosity led me to investigate further with DBCC PAGE. To my surprise, SQL Server really wasn’t persisting my parsed JSON values on the data pages; it was however persisting the parsed JSON property on the index pages.

One more SQL Server mystery revealed.

Thank you.

Thank you for running this competition and giving people the opportunity to receive world-class training.

Additionally, thank you for all of the blog posts, newsletters (book reviews!), Pluralsight courses, and everything else you do to help the SQL community; I have benefited tremendously from all of these resources over the years.

Thanks for reading. You might also enjoy following me on Twitter.

Want to learn even more SQL?

Sign up for my newsletter to receive weekly SQL tips!