Blogs

SQL Server Missing Indexes: How to Find and Fix Them

Slow queries in production rarely start slow. They start fast, then drift as the data grows and the indexes stop fitting the workload. The fastest win in SQL Server performance tuning is finding and adding the indexes that the query optimiser keeps asking for.

According to codingvila.com, SQL Server can identify and recommend missing indexes directly from the actual execution plan. Here's how to read the hints, what the two index types actually do, and when to ignore the suggestions.

At a glance:

  • SQL Server can suggest missing indexes from the actual execution plan.
  • Clustered indexes sort and store rows physically by the key. Only one per table.
  • Non-clustered indexes are separate structures pointing back to the data.
  • Suggestions are hints, not commands. Always test before applying.
  • Indexes speed up reads but slow down writes, so don't over-index.

How SQL Server tells you what it wants

When SQL Server compiles and runs a query, the optimiser analyses the workload and looks for indexes that would help. If it can't, it leaves a hint in the execution plan output. According to codingvila.com, the actual execution plan exposes these suggestions directly.

To view the actual execution plan in SQL Server Management Studio, click "Include Actual Execution Plan" (Ctrl+M) before running your query, or use the toolbar button. After the query runs, the Execution Plan tab appears with a green "Missing Index" message at the top. Right-click it to see the suggested CREATE INDEX statement.

The suggestion includes the table, the columns to index, and the columns to include as covering columns. It's the optimiser's best guess. Sometimes the guess is wrong. Test it before shipping it to production.

The two index types you actually need

SQL Server has two foundational index types. According to codingvila.com, they behave very differently:

Clustered index**: physically sorts and stores the table's rows by the key value. There can only be one per table. By default, SQL Server creates a clustered index on the primary key.

“`sql

CREATE CLUSTERED INDEX IX_table_column

ON your_table (your_column ASC);

“`

Non-clustered index**: a separate structure that contains the key and a pointer back to the data row. You can have many per table. These are your workhorse indexes for filters, joins, and search predicates.

“`sql

CREATE NONCLUSTERED INDEX IX_table_column

ON your_table (your_column ASC);

“`

For most queries, you'll use non-clustered indexes. Clustered indexes matter most when queries frequently return ranges of rows in clustered-key order, or when the table is queried mostly by primary key.

Why missing indexes matter

A missing index is a query that the optimiser thinks could run quicker if a particular index existed. According to codingvila.com, these suggestions appear when SQL Server processes a query and would benefit from an index it can't find.

The execution plan marks them as "Missing Index" with an estimated improvement percentage. In the codingvila.com example, the optimiser estimated a meaningful improvement for the suggested index. Anything well above zero is worth investigating.

Don't blindly apply every suggestion. The optimiser doesn't know about index maintenance costs, write overhead, or storage constraints. A suggested index that improves one query but slows down many inserts across the table is a bad trade.

How to read the suggestion

When you right-click a Missing Index hint in the actual execution plan, you get a CREATE statement template. It looks something like:

“`sql

CREATE NONCLUSTERED INDEX IX_name

ON dbo.TableName (column1)

INCLUDE (column2, column3);

“`

The key columns are the ones in your WHERE, JOIN, or ORDER BY clauses. The INCLUDE columns are the ones referenced in SELECT that should travel with the index so SQL Server doesn't have to do a lookup back to the clustered index.

A covering index (one where every column the query needs is either a key or in INCLUDE) can turn a table scan into an index seek. That's where the biggest wins come from.

Worked example: a slow report query

Say you have two tables, `tblOrders` and `tblCustomers`. You run this query and it feels sluggish:

“`sql

SELECT o.OrderId, c.CustomerName

FROM tblOrders o

JOIN tblCustomers c ON o.CustomerId = c.CustomerId

WHERE o.OrderDate > '2023-01-01';

“`

The execution plan shows a clustered index scan on `tblOrders` and a missing index hint suggesting:

“`sql

CREATE NONCLUSTERED INDEX IX_tblOrders_OrderDate

ON dbo.tblOrders (OrderDate)

INCLUDE (CustomerId);

“`

After creating the index, the optimiser uses the new index to seek directly to rows past the filter date, then includes the CustomerId to do the join without a key lookup. The speedup is often dramatic: scans become seeks, and queries that took seconds complete in milliseconds.

Our analysis

Missing index hints are the lowest-hanging fruit in SQL Server performance tuning. They're free, they're specific, and they usually work. The risk is over-indexing: every index speeds up reads but slows down writes and burns storage.

The discipline is to test every suggestion against realistic workloads. Run the query with and without the index on a staging environment with production-like data. Check the impact on inserts, updates, and deletes on the same table. If the write cost is too high, consider a filtered index, or skip the suggestion entirely.

Who benefits most here: developers running reports against large tables, and anyone inheriting a database nobody has tuned in years. Who should be cautious: teams with very high write throughput, where every extra index adds measurable cost.

What to watch next: SQL Server also has the "Missing Indexes" DMVs (`sys.dm_db_missing_index_*`) which aggregate suggestions across the server. That's the right tool for finding systemic gaps, not just one-off query plans.

Bottom line: read the missing index hints, test the suggestions, and don't apply them blindly. The optimiser is usually right but not always.

Key takeaways

  • Enable "Include Actual Execution Plan" to see missing index suggestions.
  • Clustered indexes sort rows physically; only one per table.
  • Non-clustered indexes are separate structures; you can have many.
  • Test every suggested index on production-like data before applying.
  • Don't over-index; every index slows down writes.

Frequently asked questions

How do I view the actual execution plan in SQL Server?

In SSMS, press Ctrl+M before running the query, or click "Include Actual Execution Plan" from the toolbar. The plan appears in a separate tab.

What's the difference between clustered and non-clustered indexes?

A clustered index physically sorts and stores rows by the key. A non-clustered index is a separate structure that points back to the data. Only one clustered index per table; many non-clustered indexes allowed.

Should I apply every missing index suggestion?

No. Test each one against realistic workloads. Some suggestions have high write costs that outweigh the read benefits.

What's a covering index?

A covering index includes every column a query needs (as keys or via INCLUDE), so SQL Server can answer the query from the index alone without touching the base table.

Where can I find missing indexes across the whole server?

Query the dynamic management views `sys.dm_db_missing_index_group_stats`, `sys.dm_db_missing_index_groups`, and `sys.dm_db_missing_index_details`.

Related