Yes, that's exactly what happens:
- SQL Server searches for your search value in the non-clustered index
- if a match is found, in that index entry, there's also the clustering key (the column or columns that make up the clustered index)
- with that clustered key, a key lookup (often also called bookmark lookup) is now performed - the clustered index is searched for that value given
- when the item is found, the entire data record at the leaf level of the clustered index navigation structure is present and can be returned
SQL Server does this, because using a physical address would be really really bad:
- if a page split occurs, all the entries that are moved to a new page would be updated
- for all those entries, all nonclustered indices would also have to be updated
and this is really really bad for performance.
This is one of the reasons why it is beneficial to use limited column lists in SELECT
(instead of always SELECT *
) and possibly even include a few extra columns in the nonclustered index (to make it a covering index). That way, you can avoid unnecessary and expensive bookmark lookups.
And because the clustering key is included in each and every nonclustered index, it's highly important that this be a small and narrow key - optimally an INT IDENTITY
or something like that - and not a huge structure; the clustering key is the most replicated data structure in SQL Server and should be a small as possible.
The fact that these bookmark lookups are relatively expensive is also one of the reasons why the query optimizer might opt for an index scan as soon as you select a larger number of rows - at at time, just scanning the clustered index might be cheaper than doing a lot of key lookups.