Skip to main content

NonClustered Index

Editorial

Introduction

While a clustered index defines the physical order of data in a table, you often need to search by columns other than the clustered key. This is where nonclustered indexes come in. A nonclustered index is a completely separate structure from the table data that acts like a lookup reference.

In this tutorial, you will learn:

  • What a nonclustered index is and how it differs from a clustered index
  • The internal structure of a nonclustered index
  • What a Key Lookup (bookmark lookup) is
  • How covering indexes eliminate lookups
  • How INCLUDE columns work
  • When and why to create nonclustered indexes

What is a NonClustered Index?

A nonclustered index is a separate data structure that contains a copy of selected columns from the table, sorted in a specific order, along with a pointer back to the full row in the table.

Think of it like the index at the back of a textbook. The index is a separate section from the actual content. It contains keywords sorted alphabetically, and each keyword has page numbers that tell you where to find the full content.

Generated visual representation from text diagram for What is a NonClustered Index?.

Key Properties

PropertyDetail
Separate structureLives outside the main table data
Multiple allowedUp to 999 nonclustered indexes per table
Contains pointersEach entry points back to the corresponding row in the table
Sorted independentlySorted by the indexed column(s), regardless of table order
Smaller than tableContains only the indexed columns, not the full row

Internal Structure

Like a clustered index, a nonclustered index uses a B-tree structure. But there is one critical difference: the leaf level does NOT contain the actual data rows. Instead, it contains the indexed column values plus a row locator that points back to the table.

What is the Row Locator?

The pointer stored in the nonclustered index depends on whether the table has a clustered index:

Table TypeRow Locator Contains
Table with clustered indexThe clustered index key value
Heap (no clustered index)A Row Identifier (RID) = File:Page:Slot
B-tree diagram of a nonclustered index showing leaf nodes containing index keys plus row locators pointing back to the data table

Key Lookup (Bookmark Lookup)

When a query uses a nonclustered index but needs columns that are not in the index, SQL Server must perform an extra step called a Key Lookup (also known as a Bookmark Lookup).

Example Scenario

-- Nonclustered index exists on customer_id
-- But query also needs order_status and order_date

SELECT order_id, customer_id, order_status, order_purchase_timestamp
FROM orders
WHERE customer_id = 'CUST_12345';

How It Works

Generated visual representation from text diagram for Key Lookup (Bookmark Lookup).

Key lookups are the main performance concern with nonclustered indexes. If too many lookups are needed, SQL Server may decide the nonclustered index is not worth using and fall back to a full scan.

Covering Indexes and INCLUDE Columns

The solution to key lookups is to create a covering index — an index that contains all the columns the query needs, so no key lookup is required.

Using INCLUDE Columns

You can add extra columns to a nonclustered index using the INCLUDE clause. These columns are stored in the leaf level of the index but are NOT part of the sort key.

-- Create a covering index
CREATE NONCLUSTERED INDEX IX_Orders_CustomerID
ON orders (customer_id)
INCLUDE (order_status, order_purchase_timestamp);

Now, the previous query can be satisfied entirely from the index:

Generated visual representation from text diagram for Covering Indexes and INCLUDE Columns.

Key Columns vs INCLUDE Columns

FeatureKey ColumnsINCLUDE Columns
SortedYes — used for seeking/scanningNo — just stored in leaf
Used in WHERE/JOIN/ORDER BYYesNo (not useful for filtering)
PurposeEnable index seeksAvoid key lookups
Stored inAll levels of the B-treeLeaf level only
Size limitUp to 16 columns, 900 bytesUp to 1023 columns

When to Create NonClustered Indexes

Good Candidates for NonClustered Indexes

ScenarioExample
Columns in WHERE clausesWHERE customer_id = ...
Columns in JOIN conditionsON orders.customer_id = customers.id
Columns in ORDER BYORDER BY order_date DESC
Foreign key columnsSpeeds up referential integrity checks
Frequently searched columnsColumns users commonly filter on

Warning Signs of Too Many Indexes

WarningWhy It Matters
Slow INSERT/UPDATE/DELETEEvery write must update all indexes
Excessive storage usageEach index consumes disk space
Index not being usedWasted space and maintenance overhead
Overlapping indexesRedundant indexes serving the same queries

Summary

Here is what you should remember about nonclustered indexes:

ConceptKey Takeaway
WhatA separate B-tree structure that points back to table data
LimitUp to 999 per table
Leaf levelContains index key + row locator (not full data rows)
Key LookupExtra step needed when query needs columns not in the index
Covering IndexAn index that contains all columns a query needs
INCLUDEAdds columns to the leaf level without making them sort keys
Best forPoint lookups, foreign keys, frequently filtered columns

Clustered vs NonClustered Quick Reference

AspectClusteredNonClustered
Contains dataYes (leaf = data)No (leaf = pointer)
Per table1Up to 999
Physical orderDefines itIndependent
Lookup neededNeverSometimes (key lookup)

In the next tutorial, we will do a detailed side-by-side comparison of clustered versus nonclustered indexes.