По материалам статьи Craig Freedman:
Scans vs. Seeks
Просмотр и поиск, это итераторы, которые в SQL Server используются для чтения данных
из таблиц и индексов. Это самые фундаментальные итераторы из числа поддерживаемых.
Их можно видеть почти в каждом плане запроса.
Каково различие между просмотром и поиском?
Просмотр проходит всю таблицу или индекс целиком. Поиск эффективно возвращает строки
одного или нескольких диапазонов индекса, указанных предикатом. Например, рассмотрим
следующий запрос:
select OrderDate from Orders where OrderKey = 2
|
[В начало]
Просмотр
Во время просмотра, будут читаться все строки в таблице Orders, оцениваемые предикатом,
"where OrderKey = 2" и, если предикат истинен (то есть, если строка
квалифицирована), эта строка будет возвращена. В этом случае, хотелось обратить
Ваше внимание на то, что предикат будет использоваться как "остаточный" предикат.
Для повышения производительности, разработчики старались, что бы оценка остаточного
предиката присутствовала непосредственно в просмотре. Однако, если предикат обходиться
слишком дорого, его оценку может переместиться в отдельный фильтр итератор.
Остаточный предикат появляется в плане исполнения с ключевым словом WHERE или в
XML плане в тэге <Predicate>.
Ниже представлен для краткости немного отредактированный план исполнения предыдущего
запроса, с использованием просмотра:
|--Table Scan(OBJECT:([ORDERS]), WHERE:([ORDERKEY]=(2)))
|
Рисунок ниже иллюстрирует просмотр:
Так как просмотр проходит каждую строку в таблице, включая те, которые не будут
квалифицированы, стоимость получается пропорциональной общему числу строк в таблице.
Таким образом, просмотр эффективен, если таблица маленькая или если большинство строк
будут квалифицированы предикатом. Однако, если таблица большая и если большинство строк
не будут квалифицированы, будет обработано больше чем необходимо страниц и строк, и
выполнено много лишних операций ввода-вывода.
[В начало]
Поиск
Возвратимся к нашему примеру, и если мы построим индекс по OrderKey, тогда с поиском
план исполнения будет выглядеть лучше. Когда в плане присутствует поиск, для перехода
к нужным строкам используется индекс. В этом случае, о предикате можно говорить,
как о "поисковом" предикате. Индекс гарантирует, что поисковый предикат возвращает
только те строки, которые квалифицированы. Этот предикат появляется в тексте плана
исполнения с ключевым словом SEEK или в XML плане с тэгом <SeekPredicates>.
Ниже показан текст плана исполнения для того же самого запроса, но с использованием
поиска:
|--Index Seek(OBJECT:([ORDERS].[OKEY_IDX]), SEEK:([ORDERKEY]=(2)) ORDERED FORWARD)
|
Следующий рисунок иллюстрирует поиск:
С самого начала поиск обрабатывает только те строки, которые квалифицированы, и
страницы, которые содержат эти квалифицированные строки, поэтому стоимость пропорциональна
числу квалифицированных строк и содержащих их страниц, а не к общему числу строк
в таблице. Таким образом, поиск является более эффективной стратегией, если мы
имеем дело с очень селективным поисковым предикатом; то есть если мы имеем поисковый
предикат, который отсекает б?льшую часть таблицы.
[В начало]
Примечание о плане исполнения
В плане исполнения, разница между просмотром и поиском определяется тем, просматривается
ли куча (объект без индекса), кластеризованный индекс или некластеризованный индекс.
Представленная ниже таблица показывает все возможные комбинации:
|
Scan
|
Seek
|
Heap
|
Table Scan
|
|
Clustered Index
|
Clustered Index Scan
|
Clustered Index Seek
|
Non-clustered Index
|
Index Scan
|
Index Seek
|
[В начало]
Что будет дальше …
Есть ещё много интересного, что можно рассказать о просмотре и поиске. В своей следующей
статье я расскажу о bookmark lookup и как bookmark lookup работает при просмотре
и поиске.
[В начало]