Advanced SQL & Data Engineering • Training 07
Article-Training • SQL Server–Friendly Series

SARGability

Write SQL That Can Actually Use an Index

SARGability means writing predicates SQL Server can search efficiently.

Searchable Column → Selective Predicate → Index Seek Opportunity → Fewer Reads → Faster Query
Bad: YEAR(Date)
→
Scan Risk
Good: Date Range
→
Seek Opportunity
8learning modules
24interactive practices
5rapid review questions
50%certificate threshold
Learning target
Rewrite predicates so indexed columns remain searchable and efficient.
Practice progress0 / 24

Complete 12 of 24 practices (50%) and enter your name to unlock the Certificate of Participation.

MODULE 01
🎯

What SARGability Really Means

A SARGable predicate is written so SQL Server can use an index key to narrow the search efficiently. The core principle is simple: keep the indexed column exposed in a searchable comparison whenever possible.

🎯
Search the column; do not transform every row first

If SQL Server must calculate YEAR(OrderDate) for every row before deciding whether it matches, the engine may lose the direct ability to navigate the OrderDate index by range.

Core ideas

  • Search arguments should align with indexed key values
  • Functions on indexed columns often reduce seek opportunities
  • Range predicates are often stronger than transformed-column predicates
  • Validate with actual plans and logical reads
Bad vs better
-- Less SARGable
WHERE YEAR(OrderDate) = 2026

-- More SARGable
WHERE OrderDate >= '2026-01-01'
  AND OrderDate <  '2027-01-01';
✅

SARGability is about preserving the engine's ability to navigate the index key directly.

Practice — 3 cases

Practice 1 / Práctica 1
What does SARGable mean in practical SQL Server terms?
Practice 2 / Práctica 2
Which predicate is generally more SARGable?
Practice 3 / Práctica 3
Why does SARGability matter?
MODULE 02
🧮

Functions on Indexed Columns

Functions can make SQL expressive, but wrapping an indexed column in a function often hides the raw key values from the access method. The usual strategy is to rewrite the predicate around the stored value.

🎯
Move the transformation away from the indexed column

Instead of transforming every LastName with LEFT(), describe the range of names that logically match the same condition.

Core ideas

  • Functions on columns can block direct index navigation
  • Rewrite to ranges or direct equality where possible
  • Do not change semantics just to chase a seek
  • Persisted computed columns can help when a transformation is truly required
String prefix rewrite
-- Less SARGable
WHERE LEFT(LastName, 1) = 'S'

-- More SARGable range
WHERE LastName >= 'S'
  AND LastName <  'T';
✅

The safest rewrite preserves business meaning while exposing the indexed value directly.

Practice — 3 cases

Practice 4 / Práctica 4
Why is applying a function to an indexed column often problematic?
Practice 5 / Práctica 5
Which rewrite is generally stronger for UPPER(CustomerCode) = 'ABC'?
Practice 6 / Práctica 6
Which pattern is usually more index-friendly?
MODULE 03
🔁

Implicit Conversions: The Hidden SARGability Killer

Even a simple equality predicate can become non-SARGable when the parameter and indexed column use incompatible data types. SQL Server follows type-precedence rules and may convert the column side.

🎯
Matching values is not enough; matching data types matters too

Comparing an nvarchar parameter to a varchar indexed column can introduce a conversion warning or conversion operator that changes the access path.

Core ideas

  • Align parameter and column data types
  • Watch for PlanAffectingConvert warnings
  • Avoid casting the indexed column as a routine fix
  • Fix type consistency in schemas, procedures and application parameters
Type alignment
-- Indexed column:
CustomerCode varchar(20)

-- Better parameter:
DECLARE @CustomerCode varchar(20);

SELECT ...
FROM dbo.Customer
WHERE CustomerCode = @CustomerCode;

-- Avoid forcing:
WHERE CONVERT(nvarchar(20), CustomerCode) = @p;
✅

Type consistency is part of query performance design, not only data modeling.

Practice — 3 cases

Practice 7 / Práctica 7
What is an implicit conversion?
Practice 8 / Práctica 8
Why can an implicit conversion hurt index usage?
Practice 9 / Práctica 9
What is the strongest fix for type mismatch in predicates?
MODULE 04
📅

Date and Time Predicates That Stay Searchable

Dates are one of the most common places where SARGability is lost. The safest pattern for periods is usually a direct half-open range: greater than or equal to the start, less than the next boundary.

🎯
Ask for the interval, not a transformed date

Instead of converting every datetime to date, define the exact interval that contains the day, month or year you want.

Core ideas

  • Use >= start and < next period
  • Avoid functions on datetime columns when a range works
  • Half-open ranges avoid precision traps
  • Date range design also helps partition elimination
Day filter
DECLARE @Day date = '2026-09-24';

SELECT ...
FROM dbo.Events
WHERE EventDate >= @Day
  AND EventDate < DATEADD(day, 1, @Day);
✅

For temporal data, a well-formed range is often both clearer and more optimizer-friendly than extracting date parts.

Practice — 3 cases

Practice 10 / Práctica 10
Why are half-open date ranges useful?
Practice 11 / Práctica 11
Which filter is generally safer for all rows on September 24, 2026?
Practice 12 / Práctica 12
What is wrong with hardcoding 23:59:59.997 as the end of every day?
MODULE 05
🧩

NULL Logic, ISNULL and OR Predicates

Convenient NULL-handling expressions can hide indexed values behind functions. The challenge is to preserve correct three-valued logic while keeping the column directly searchable where practical.

🎯
Correct NULL logic first, performance second

Do not rewrite NULL handling into something faster but semantically wrong. The best predicate keeps the business rule explicit and gives the optimizer useful access paths.

Core ideas

  • Avoid wrapping indexed columns in ISNULL when possible
  • Use explicit IS NULL logic when it matches the business rule
  • OR is not automatically bad, but can complicate selectivity
  • Filtered indexes may help targeted NULL/non-NULL patterns
Explicit NULL comparison
WHERE Status = @Status
   OR (Status IS NULL AND @Status IS NULL)

-- Possible filtered index example:
CREATE INDEX IX_Order_Open
ON dbo.Orders(OrderDate)
WHERE ClosedDate IS NULL;
✅

SARGability never justifies changing the meaning of NULL logic; correctness remains the first constraint.

Practice — 3 cases

Practice 13 / Práctica 13
Why can ISNULL(Column, value) in a predicate be problematic?
Practice 14 / Práctica 14
Which predicate may better express 'Status = @Status or both are NULL' without wrapping the column?
Practice 15 / Práctica 15
Are OR predicates always non-SARGable?
MODULE 06
🔤

LIKE, Leading Wildcards and Searchable Prefixes

B-tree indexes are strongest when SQL Server knows the beginning of the search range. A trailing wildcard preserves that starting point; a leading wildcard usually removes it.

🎯
Indexes need a place to start

LIKE 'Juan%' can navigate to the J-u-a-n range. LIKE '%Juan%' asks SQL Server to find the text anywhere inside each value, which often requires much broader work.

Core ideas

  • Trailing wildcard can preserve prefix searching
  • Leading wildcard usually prevents a normal seek range
  • Case/collation rules affect text comparisons
  • Use specialized search technology for true substring-heavy workloads
Prefix vs substring
-- More index-friendly:
WHERE LastName LIKE 'Smith%'

-- Usually broad scan-style work:
WHERE LastName LIKE '%Smith%'

-- If substring search is core:
-- evaluate Full-Text Search or
-- another search-oriented design.
✅

Do not force a B-tree index to solve a search problem it was not designed to solve.

Practice — 3 cases

Practice 16 / Práctica 16
What is the main issue with LIKE '%term'?
Practice 17 / Práctica 17
Which LIKE pattern is usually more index-friendly?
Practice 18 / Práctica 18
What should you consider when true substring search is a core requirement?
MODULE 07
🧱

Computed Columns: When the Transformation Is the Business Key

Sometimes you cannot remove the transformation because users truly search by that transformed value. In those cases, a computed column can make the transformed value part of the schema and potentially index it.

🎯
If the business searches the transformation, model the transformation

If every query searches a normalized phone number or date bucket, repeatedly computing it in WHERE may be a signal that the transformed value deserves a modeled, indexable representation.

Core ideas

  • Computed columns can expose transformed values as schema elements
  • Persisted computed columns store the computed value physically
  • Indexability rules still apply
  • Use when the transformation is a stable, recurring search pattern
Computed-column pattern
ALTER TABLE dbo.Customer
ADD NormalizedPhone AS
(
    REPLACE(REPLACE(REPLACE(Phone,'-',''),'(',''),')','')
) PERSISTED;

CREATE INDEX IX_Customer_NormalizedPhone
ON dbo.Customer(NormalizedPhone);

SELECT ...
FROM dbo.Customer
WHERE NormalizedPhone = @NormalizedPhone;
✅

Computed columns are a schema-level answer when a transformation is unavoidable and repeatedly searched.

Practice — 3 cases

Practice 19 / Práctica 19
When can a computed column improve SARGability?
Practice 20 / Práctica 20
What is an important requirement for indexing a computed column?
Practice 21 / Práctica 21
Why might a persisted computed column be useful?
MODULE 08
🏭

Production Workflow: Rewrite, Measure, Verify

SARGability is a tuning principle, not a religion. A seek is not automatically better than a scan, and some transformations are necessary. The goal is to remove avoidable barriers between the predicate and the index key, then prove the benefit.

🎯
Rewrite only what the evidence says is hurting

If a non-SARGable predicate scans 20 rows, there may be nothing worth fixing. If it scans 200 million rows to return 12, the rewrite may be transformational.

Core ideas

  • Capture actual plan and STATISTICS IO/TIME
  • Identify functions, conversions and wildcard patterns on key columns
  • Rewrite without changing business semantics
  • Verify reads, CPU, elapsed time and result correctness
SARGability checklist
1. Which predicate is expensive?
2. Is an indexed column wrapped in a function?
3. Is there an implicit conversion?
4. Can a date-part test become a range?
5. Is a leading wildcard unavoidable?
6. Is NULL logic explicit and correct?
7. Would a computed column model a required transformation?
8. Are logical reads lower after the rewrite?
9. Is the new result set exactly equivalent?
10. Does the actual plan improve under representative data?
✅

The strongest SARGable query is the one that remains correct and gives SQL Server a better access path under real workload conditions.

Practice — 3 cases

Practice 22 / Práctica 22
What is the best way to prove a SARGable rewrite helped?
Practice 23 / Práctica 23
Which sequence is strongest for tuning a non-SARGable predicate?
Practice 24 / Práctica 24
What is the strongest production rule for SARGability?
5-Question Knowledge Check

Can you recognize and rewrite non-SARGable predicates?

Open each item after answering it in your own words. The 24 interactive practices above drive certificate progress.

1. What is the simplest definition of a SARGable predicate?

A predicate written so SQL Server can search indexed key values efficiently.

2. Why is YEAR(OrderDate) = 2026 often weaker than a direct date range?

The function transforms the indexed column; a direct range exposes searchable boundaries.

3. How can implicit conversions hurt performance?

SQL Server may convert the indexed column side and reduce seek opportunities.

4. Why is LIKE 'abc%' usually stronger than LIKE '%abc%' for a normal B-tree index?

The known prefix gives SQL Server a starting key range.

5. How do you validate a SARGable rewrite?

Confirm identical results and compare actual runtime evidence.

SARGability Rewrite Map

Common patterns to recognize quickly

Less searchable patternBetter direction
YEAR(DateCol) = 2026DateCol >= start AND DateCol < next_start
LEFT(Name,1) = 'S'Name >= 'S' AND Name < 'T'
CONVERT(..., IndexedCol) = @pMatch parameter type to IndexedCol
LIKE '%term%'Use prefix search or search-specific technology
ISNULL(Col,'') = @pUse explicit NULL logic when semantically equivalent

Certificate of Participation

Complete at least 12 of the 24 practice cases (50%) and enter your name.

0 / 24 • 0%
Production note

SARGability is about removing avoidable barriers between predicates and index keys.