15.11.24

Scans vs Seeks

Автор: Craig Freedman Scans vs. Seeks

Scan и Seek — это итераторы, которые SQL Server использует для чтения данных из таблиц и индексов. Эти итераторы являются одними из самых фундаментальных, которые можно встретить почти в каждом в плане запроса. Так в чем разница между Scan (просмотром) и Seek (поиском)?

Просмотр возвращает всю таблицу или индекс. Поиск возвращает строки из одного или нескольких диапазонов индекса на основе предиката. Например, рассмотрим следующий запрос:

select OrderDate from Orders where OrderKey = 2

Просмотр

При просмотре мы считываем каждую строку из таблицы Orders, оцениваем предикат «where OrderKey = 2» и, если предикат истинен (т. е. если строка соответствует требованиям), возвращаем эту строку. В таком случае мы называем предикат «residual (остаточным)» предикатом. В целях повышения производительности, мы оцениваем остаточный предикат при просмотре только по возможности. Однако, если такой предикат слишком затратен, мы можем применить его отдельно, в итераторе фильтра. Остаточный предикат появляется в текстовом представлении плана после ключевого слова WHERE, а в XML-представлении плана с тегом <Predicate>.

Вот текстовое представление плана (слегка отредактированное для краткости) нашего запроса, где наблюдаем просмотр:

  |--Table Scan(OBJECT:([ORDERS]), WHERE:([ORDERKEY]=(2)))

Следующий рисунок иллюстрирует просмотр:

Поскольку просмотр затрагивает все строки таблицы, независимо от того, соответствует она предикату или нет, стоимость плана пропорциональна общему количеству строк в таблице. Таким образом, просмотр является эффективной стратегией, если таблица небольшая или если большинство строк соответствуют предикату. Однако, если таблица большая или большинство строк не соответствуют предикату, будет затронуто гораздо больше страниц и строк, а значит выполнено чересчур много операций ввода-вывода.

Поиск

Вернёмся к нашему примеру, если у нас есть индекс по OrderKey, лучшим планом может быть Поиск (seek). При поиске мы используем индекс для прямого перехода к тем строкам, которые удовлетворяют предикату. В этом случае мы называем предикат «Поисковым» предикатом. В большинстве случаев нам не нужно повторно оценивать поисковый предикат как остаточный предикат. Индекс гарантирует, что поиск возвращает только те строки, которые соответствуют требованиям. Поисковый предикат показан в текстовом представлении плана с ключевым словом 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

Комментариев нет:

Отправить комментарий