DEV_NET_CORE
GET_STARTED
SQLQuery tuning, Query Store, and plan stability

Knowing when to change SQL, indexes, or schema instead of forcing hints

Overview

Knowing when to change SQL, indexes, or schema instead of forcing hints is a core SQL Server tuning judgment. Query hints, table hints, forced plans, and Query Store hints can be useful, but they are usually targeted interventions. They tell the optimizer to behave in a particular way without necessarily fixing the reason the optimizer struggled.

Durable tuning often comes from improving the query shape, giving the optimizer better indexes and statistics, or changing a schema that makes efficient access impossible. A hint may be the right short-term mitigation during an incident, but it can become technical debt if it locks the system into a plan that no longer fits the data.

For interviews, this topic matters because it separates candidates who can memorize hints from candidates who can diagnose root causes. Strong answers explain the trade-off: hints can stabilize a known problem quickly, while SQL, index, statistics, or schema changes usually address the underlying data access pattern.

Core Concepts

What Hints Do

Hints influence the optimizer's choices. They can affect join strategy, memory grants, degree of parallelism, recompilation, index access, locking behavior, cardinality-related behavior, and other plan decisions.

Examples include:

  • OPTION (RECOMPILE).
  • OPTIMIZE FOR.
  • MAXDOP.
  • Join hints such as HASH JOIN, MERGE JOIN, and LOOP JOIN.
  • Table hints such as FORCESEEK.
  • Query Store hints.
  • Query Store plan forcing.

Hints can be helpful, but they should usually be applied after understanding the cause.

Why Hints Are Risky

Hints can make a plan less adaptable. SQL Server's optimizer normally considers statistics, indexes, cardinality estimates, costing, available operators, and compatibility-level features. A hint narrows the search or overrides part of the decision.

Risks include:

  • The hint works for one data distribution but fails later.
  • The hint helps one parameter value and hurts another.
  • The hint hides missing indexes or poor SQL shape.
  • The hint becomes stale after schema or data changes.
  • The hint prevents newer optimizer features from helping.
  • The hint makes future troubleshooting harder.
  • Some hints can prevent a valid plan and cause errors.

Hints are not bad by definition. They are sharp tools.

When Hints Are Reasonable

Hints can be reasonable when:

  • There is a production incident and a quick reversible mitigation is needed.
  • A known plan regression needs temporary stabilization.
  • Application SQL cannot be changed quickly.
  • Vendor or ORM-generated SQL is hard to modify.
  • A specific optimizer issue is well understood and narrowly scoped.
  • A compatibility-level upgrade needs a temporary targeted workaround.
  • The hint has been tested across representative parameter values.
  • The hint has an owner, reason, monitoring plan, and removal condition.

Query Store hints are especially useful when you need to shape a query plan without changing application code.

Prefer SQL Changes When The Query Shape Is The Problem

Change the SQL when the text asks the database to do unnecessary or inefficient work.

Common SQL issues include:

  • Non-SARGable predicates.
  • Functions on indexed columns.
  • Implicit conversions.
  • Unnecessary SELECT *.
  • Optional predicates that force generic plans.
  • Joins that accidentally multiply rows.
  • Filters applied after large intermediate results.
  • Repeated scalar UDF calls.
  • Correlated subqueries that obscure intent.
  • Overly broad result sets.

Example:

Code
-- Poor shape: function on the column prevents a simple date range seek
WHERE CONVERT(date, OrderDate) = @OrderDate;

Better:

Code
WHERE OrderDate >= @OrderDate
  AND OrderDate < DATEADD(day, 1, @OrderDate);

A hint may force a seek, but rewriting the predicate makes the query naturally seekable.

Prefer Index Changes When Access Paths Are Missing

Change indexes when the query is well-shaped but lacks an efficient access path.

Index change signals include:

  • Large scans for selective predicates.
  • Expensive key lookups repeated many times.
  • Sort operators that match common ORDER BY patterns.
  • Joins on unindexed foreign key columns.
  • High logical reads from hot queries.
  • Query Store shows high total read cost.
  • A covering index would eliminate repeated base-table access.
  • A filtered index would support a common subset.

Example:

Code
CREATE INDEX IX_Orders_Status_OrderDate
ON dbo.Orders (Status, OrderDate DESC)
INCLUDE (CustomerId, TotalAmount);

This can be better than forcing an index because it gives the optimizer a useful access path while still allowing cost-based decisions.

Avoid Over-Indexing

Indexes are not free.

Every additional index can add:

  • Storage cost.
  • Memory pressure.
  • Insert, update, delete, and merge overhead.
  • Transaction log volume.
  • Maintenance work.
  • Potential blocking or concurrency pressure.
  • More optimizer choices to evaluate.

Before adding an index:

  • Check existing indexes for overlap.
  • Consider modifying an existing index.
  • Validate the query workload, not one plan.
  • Estimate write impact.
  • Monitor usage after deployment.
  • Remove unused or duplicate indexes carefully.

Prefer Statistics Changes When Estimates Are The Problem

Change statistics or statistics strategy when poor cardinality estimates are driving bad plans.

Signals include:

  • Estimated rows differ greatly from actual rows.
  • Data distribution changed recently.
  • A large load, delete, or archive happened.
  • Queries use correlated columns.
  • Filtered subsets need better estimates.
  • Parameter-sensitive behavior depends on skew.

Example:

Code
UPDATE STATISTICS dbo.Orders IX_Orders_Status_OrderDate WITH FULLSCAN;

Or create filtered statistics for a hot subset:

Code
CREATE STATISTICS ST_Orders_Open_Status
ON dbo.Orders (Status)
WHERE Status IN ('Pending', 'Processing');

Do not blindly update all statistics as a substitute for diagnosis, but do consider statistics when estimates are clearly wrong.

Prefer Schema Changes When The Model Blocks Efficient Queries

Change schema when the data model makes efficient access, integrity, or cardinality estimation difficult.

Schema problem signals include:

  • Comma-separated IDs in a string column.
  • JSON or XML used for frequently filtered relational attributes.
  • Wrong data types causing implicit conversions.
  • Missing constraints for known uniqueness or relationships.
  • Low-quality surrogate fields replacing real searchable columns.
  • Entity-attribute-value design for normal transactional queries.
  • Repeated denormalized columns that drift out of sync.
  • Date/time values stored as strings.
  • Tenant or partitioning design that fights common access patterns.

Example schema issue:

Code
-- Bad for filtering, joining, validation, and indexing
CREATE TABLE dbo.CustomerPreference
(
    CustomerId int NOT NULL,
    PreferenceIds varchar(2000) NOT NULL
);

Better relational design:

Code
CREATE TABLE dbo.CustomerPreference
(
    CustomerId int NOT NULL,
    PreferenceId int NOT NULL,
    CONSTRAINT PK_CustomerPreference
        PRIMARY KEY (CustomerId, PreferenceId)
);

No hint can make a poor data model fully behave like a well-modeled relational structure.

SARGability Before Hints

SARGable predicates can use indexes efficiently. Non-SARGable predicates often force scans or residual predicates.

Common non-SARGable patterns:

Code
WHERE LEFT(LastName, 1) = 'S';
WHERE ISNULL(Status, '') = 'Open';
WHERE YEAR(OrderDate) = 2026;
WHERE CONVERT(varchar(10), CreatedAt, 120) = '2026-06-20';

Better patterns:

Code
WHERE LastName >= 'S' AND LastName < 'T';
WHERE Status = 'Open';
WHERE OrderDate >= '20260101' AND OrderDate < '20270101';
WHERE CreatedAt >= '20260620' AND CreatedAt < '20260621';

If the predicate is not seekable, forcing a seek may be less useful than fixing the predicate.

Parameter Sensitivity

Parameter-sensitive plans are a common reason people reach for hints. A plan optimized for a rare value may be bad for a common value, and a plan optimized for a common value may be bad for a rare value.

Possible fixes include:

  • Query rewrite.
  • Branching for distinct cases.
  • Safe dynamic SQL for optional filters.
  • OPTION (RECOMPILE) for suitable statements.
  • OPTIMIZE FOR when a representative value exists.
  • Parameter Sensitive Plan optimization in newer SQL Server versions.
  • Query Store plan forcing only when one plan is good enough for the workload.

The right answer depends on data skew, execution frequency, compile cost, and workload mix.

Query Store Hints Vs Code Changes

Query Store hints are useful when the SQL text cannot be changed quickly. They can apply hints without editing application code.

Use Query Store hints when:

  • The SQL comes from an ORM or vendor package.
  • Deployment lead time is too long for an incident.
  • You need a reversible production mitigation.
  • You want to test a targeted hint safely.

Prefer code changes when:

  • The query is clearly written inefficiently.
  • The application can be deployed safely.
  • The fix improves clarity and maintainability.
  • The query needs different logic, not just a different plan choice.

Plan Forcing Vs Root Cause Fixes

Query Store plan forcing can stabilize a query by making SQL Server try to use a previously captured plan.

This is useful when:

  • A query regressed because of a plan choice change.
  • A previous plan is known to be better for most workload cases.
  • A quick mitigation is needed.

It is less appropriate when:

  • Data distribution is changing quickly.
  • The query is parameter-sensitive and needs multiple plan shapes.
  • The old plan relies on obsolete indexes.
  • The root problem is bad SQL or schema.
  • You have not tested representative parameter values.

Plan forcing should have a review date. Otherwise, it quietly becomes permanent technical debt.

Decision Framework

Use this decision flow:

EvidencePrefer
Predicate is non-SARGableChange SQL
Query returns or joins unnecessary rowsChange SQL
Access path is missing for a good queryChange indexes
Existing indexes overlap heavilyModify indexes
Estimates are wrong because statistics are stale or incompleteUpdate or create statistics
Data model stores relational data in strings or generic attributesChange schema
Query is generated and cannot be changed quicklyQuery Store hint may be appropriate
Known plan regression needs emergency mitigationPlan forcing may be appropriate
One plan is bad for different parameter groupsRewrite, branch, dynamic SQL, PSP optimization, or recompile

The stronger the root-cause evidence, the less attractive a hint becomes.

Common Mistakes

Common mistakes include:

  • Adding hints because they made one test faster.
  • Forcing an index without checking write cost or index overlap.
  • Using NOLOCK to hide blocking while accepting inconsistent reads.
  • Applying OPTION (RECOMPILE) to high-frequency lightweight queries.
  • Forcing one plan for a parameter-sensitive query.
  • Ignoring implicit conversions caused by mismatched data types.
  • Treating missing index suggestions as automatic instructions.
  • Leaving Query Store hints undocumented.
  • Forgetting to revisit forced plans after data changes.
  • Using hints to avoid fixing a broken data model.

Best Practices

Best practices include:

  • Start with evidence from Query Store, actual execution plans, waits, and workload metrics.
  • Understand the root cause before choosing a fix.
  • Prefer SQL rewrites for bad query shape.
  • Prefer index changes for missing access paths.
  • Prefer statistics work for bad estimates.
  • Prefer schema changes for structural modeling problems.
  • Use hints as targeted, documented, monitored interventions.
  • Test with representative parameter values and data volume.
  • Validate workload-level impact after release.
  • Remove or revisit hints when the durable fix is available.

Interview Practice

PreviousBaselines, workload comparisons, and targeted tuningNext UpParameter-sensitive plans and skewed data distributions