Для довольно сложного запроса, который я пытаюсь оптимизировать, я заметил, что удаление TOP n
предложения меняет план выполнения. Я бы предположил, что когда запрос включает TOP n
в себя механизм базы данных, он будет запускать запрос, игнорируя TOP
предложение, а затем в конце просто сократит этот результат до n запрошенных строк. Графический план выполнения, кажется, указывает на то, что это так - TOP
это «последний» шаг. Но, похоже, что-то еще происходит.
Мой вопрос: как (и почему) предложение TOP n влияет на план выполнения запроса?
Вот упрощенная версия того, что происходит в моем случае:
Запрос сопоставляет строки из двух таблиц A и B.
Без этого TOP
предложения оптимизатор оценивает, что будет 19k строк из таблицы A и 46k строк из таблицы B. Фактическое число возвращаемых строк составляет 16k для A и 13k для B. Совпадение хеша используется для объединения этих двух наборов результатов для всего 69 строк (затем применяется сортировка). Этот запрос происходит очень быстро.
Когда я добавляю, TOP 1001
оптимизатор не использует хеш-соответствие; вместо этого он сначала сортирует результаты из таблицы A (та же самая оценка / факт 19k / 16k) и выполняет вложенный цикл для таблицы B. Предполагаемое число строк для таблицы B теперь равно 1, и странно то, что TOP n
непосредственно влияет на оценочное количество казней (поиск по индексу) против B - оно всегда равно 2n + 1 , или в моем случае 2003. Эта оценка изменяется соответственно, если я изменяюсь TOP n
. Конечно, поскольку это вложенное соединение, фактическое количество выполнений составляет 16 КБ (количество строк в таблице А), и это замедляет запрос.
Реальный сценарий немного сложнее, но он отражает основную идею / поведение. Обе таблицы ищутся с использованием индекса поиска. Это выпуск SQL Server 2008 R2 Enterprise.
ORDER BY
пункт. ДобавляяTOP
изменения, где в плане происходит такая сортировка, но я больше обеспокоен тем, как это влияет на количество выполнений поиска индекса по таблице B ... (конечно, эти два могут быть связаны - я не знаю)FAST num_rows
подсказка запроса.Ответы:
То, как сформулировано выше, заставляет меня думать, что у вас может быть неправильное представление о том, как выполняется запрос. Оператор в плане запроса не является шагом (где полный набор результатов предыдущего шага оценивается следующим.
SQL Server использует конвейерную модель выполнения, где каждый оператор предоставляет такие методы, как Init () , GetRow () и Close () . Как следует из названия GetRow () , оператор создает одну строку за раз по требованию (как того требует его родительский оператор). Это задокументировано в справочнике по логическим и физическим операторам Books Online , более подробно в моем блоге « Почему планы запросов выполняются задом наперед» . Эта рядовая модель необходима для формирования интуитивной интуиции при выполнении запросов.
Некоторые логические операции, такие как
TOP
, полусоединения иFAST n
подсказки запросов, влияют на то, как оптимизатор запросов обходится альтернативам плана выполнения. Основная идея заключается в том, что одна возможная форма плана может возвращать первые n строк быстрее, чем другой план, который был оптимизирован для возврата всех строк.Например, объединение индексированных вложенных циклов часто является самым быстрым способом возврата небольшого числа строк, хотя объединение хешей или объединение со сканированием может быть более эффективным на больших наборах. Оптимизатор запросов рассуждает об этих вариантах, устанавливая цель строки в определенной точке логического дерева операций.
Цель строки изменяет способ определения альтернатив плана запроса. Суть его в том, что оптимизатор начинает с того, что каждый оператор оценивает стоимость, как если бы требовался полный набор результатов, устанавливает целевую строку в соответствующей точке, а затем возвращается обратно к дереву плана, оценивая количество строк, которые он ожидает проверить. встретить цель строки.
Например, логика
TOP(10)
устанавливает целевую строку в 10 в конкретной точке логического дерева запросов. Затраты операторов, ведущих к цели строки, модифицируются, чтобы оценить, сколько строк им нужно произвести для достижения цели строки. Этот расчет может стать сложным, так что все это легче понять с помощью полностью проработанного примера и аннотированных планов выполнения. Цели строк могут влиять не только на выбор типа соединения или на то, предпочтительнее ли поиск и поиск, чем на сканирование. Подробнее об этом здесь .Как всегда, план выполнения, выбранный на основе цели строки, зависит от рассуждений оптимизатора и качества предоставляемой ему информации. Не каждый план с целью получения строк на практике будет производить необходимое количество строк быстрее, но в соответствии с моделью калькуляции это будет происходить.
В тех случаях, когда план целей строки оказывается не быстрым, обычно есть способы изменить запрос или предоставить оптимизатору более точную информацию, чтобы лучше подходил естественно выбранный план. Какой вариант подходит в вашем случае, конечно, зависит от деталей. Функция цели строки, как правило, очень эффективна (хотя есть ошибка, на которую нужно обращать внимание при использовании в параллельных планах выполнения).
Ваш конкретный запрос и план могут не подходить для подробного анализа здесь (во всех случаях, если хотите, предоставьте фактический план выполнения), но, надеюсь, идеи, изложенные здесь, позволят вам продвинуться вперед.
источник
Когда вы используете TOP, оптимизатор видит возможность выполнять меньше работы. Если вы попросите 10 рядов, то, скорее всего, вам не понадобится весь набор. Таким образом, оператор TOP может быть перемещен намного дальше вправо. Он будет продолжать запрашивать строки у следующего оператора (справа), пока не получит достаточно.
Вы указываете, что без TOP запрос сортируется в самом конце. Если движок может заранее знать, сколько строк должно быть удовлетворено объединением, он вполне может выбрать аналогичный план, расположив ТОП слева. Но при стремлении сделать Hash Match относительно высоким и, по-видимому, без возможности объединения слиянием, оптимизатор может предпочесть отфильтровать TOP дальше вправо.
Когда запрашивается таблица B, она выбирает по одной строке за раз. Вот почему оценка равна 1. Это также предполагает, что эта строка будет найдена только в 50% случаев. Так что он предполагает, что потребуется 2n + 1, чтобы найти его.
источник
TOP
пункту? Спасибо за ваш ответ (ы) / терпение.