Short Answer
If you have selective predicates earlier in the index that filter a lot of rows, the SARGability of trailing predicates matters less.
CREATE INDEX shorty ON dbo.a_table(selective_column, non_selective_column); SELECT COUNT(*) AS records FROM dbo.a_table AS a WHERE selective_column = 1 AND ISNULL(non_selective_column, 'whatever') = 'whatever';
Am I saying you should do this? Am I saying that it’s a good example to set?
No. I’m just saying you can get away with it in this situation.
Longer Answer
The less selective other predicates are, the less you can get away with it.
Take these two queries:
SELECT COUNT(*) AS records FROM dbo.Users AS u WHERE u.Id = 8 AND ISNULL(u.Location, N'') = N''; SELECT COUNT(*) AS records FROM dbo.Users AS u WHERE u.Id BETWEEN 8 AND 9693617 AND ISNULL(u.Location, N'') = N'';
The first one has an equality predicate on the Id, the primary key of the table. It’s going to touch one row, and then evaluate the residual predicate on Location.
The second query has a very non-selective range predicate on Id — still a selective column, just not a selective predicate anymore — so, we do a lot more work (relatively).
If we have this index, and we look at how four logically equivalent queries perform:
CREATE UNIQUE INDEX fast_lane ON dbo.Users(Id, Location);
SELECT COUNT(*) AS records FROM dbo.Users AS u WHERE u.Id = 8 AND ISNULL(u.Location, N'') = N''; SELECT COUNT(*) AS records FROM dbo.Users AS u WHERE u.Id BETWEEN 8 AND 9693617 AND ISNULL(u.Location, N'') = N''; SELECT COUNT(*) AS records FROM dbo.Users AS u WHERE u.Id = 8 AND ( u.Location = N'' OR u.Location IS NULL ); SELECT COUNT(*) AS records FROM dbo.Users AS u WHERE u.Id BETWEEN 8 AND 9693617 AND ( u.Location = N'' OR u.Location IS NULL );
The query plans tell us enough:
It really doesn’t matter if we obey the laws of SARGability here.
Expect Depression
There have been many times when explaining SARGability to people that they went back and cleaned up code like this to find it didn’t make much of a difference to performance. That’s because SARGability depends on indexes that can support seekable predicates. Without those indexes, it makes no practical difference how you write these queries.
Again, I’m not condoning writing Fast Food Queries when you can avoid it. Like I said earlier, it sets a bad example.
Once this kind of code creeps into your development culture, it’s hard to keep it contained.
There’s no reason to not avoid it, but sometimes it hurts more than others. For instance, if Location were the first column in the index, we’d have a very different performance profile across all of these queries, and other rewrites might start to make more sense.
Thanks for reading!
Going Further
If this is the kind of SQL Server stuff you love learning about, you’ll love my training. I’m offering a 75% discount to my blog readers if you click from here. I’m also available for consulting if you just don’t have time for that and need to solve performance problems quickly.