Самые большие проблемы у нас здесь:
- Как говорит @JNK, SQL Server скрывает использование UDF и в любом случае делает с ними ужасные вещи (как всегда, оценивает одну строку). Когда вы генерируете фактический план в SSMS, вы вообще не видите его использования. На Plan Explorer распространяются те же ограничения, поскольку он может предоставлять только информацию о плане, предоставляемом SQL Server.
- Код опирается на разные источники метрик времени выполнения при создании фактического плана. К сожалению, XML плана не включает в себя вызовы функций, и SQL Server не раскрывает операции ввода-вывода, возникающие у функций при их использовании
SET STATISTICS IO ON;
(так Table I/O
заполняется вкладка).
Рассмотрим следующий вид и функцию AdventureWorks2012. Это просто глупая попытка вернуть случайную строку из таблицы сведений с учетом случайной строки из таблицы заголовков - в основном, чтобы каждый раз генерировать как можно больше ввода-вывода.
CREATE VIEW dbo.myview
WITH SCHEMABINDING
AS
SELECT TOP (100000) rowguid, SalesOrderID, n = NEWID()
FROM Sales.SalesOrderDetail ORDER BY NEWID();
GO
CREATE FUNCTION dbo.whatever(@SalesOrderID INT)
RETURNS UNIQUEIDENTIFIER
WITH SCHEMABINDING
AS
BEGIN
RETURN
(
SELECT TOP (1) rowguid FROM dbo.myview
WHERE SalesOrderID = @SalesOrderID ORDER BY n
);
END
GO
Что Management Studio делает (и не говорит) вам
Возьмите следующий запрос в SSMS:
SET STATISTICS IO ON;
SELECT TOP (5) SalesOrderID, dbo.whatever(SalesOrderID)
FROM Sales.SalesOrderHeader ORDER BY NEWID();
SET STATISTICS IO OFF;
Когда вы оцениваете план, вы получите план запроса и в одном плане для функции (не 5, как вы могли бы надеяться):
Очевидно, вы вообще не получаете никаких данных ввода-вывода, поскольку запрос фактически не выполнялся. Теперь создайте фактический план. Вы получите 5 ожидаемых строк в таблице результатов, следующий план (который абсолютно не упоминает о UDF, за исключением того, что в XML вы можете найти его как часть текста запроса и как часть скалярного оператора):
И следующий STATISTICS IO
вывод (который абсолютно не упоминается Sales.SalesOrderDetail
, хотя мы знаем, что он должен был прочитать из этой таблицы):
Таблица «SalesOrderHeader». Сканирование 1, логическое чтение 57, физическое чтение 0, чтение с опережением 0, логическое чтение с 0, физическое чтение с 0, чтение с опережением 0.
Что вам говорит Проводник планов?
Когда PE генерирует оценочный план для того же запроса, он знает о том же, что и SSMS. Однако это показывает вещи немного более интуитивным способом. Например, оценочный план для внешнего запроса показывает, как выходные данные функции объединяются с выходными данными запроса, и сразу становится ясно - в пределах одной плановой диаграммы - что в обеих таблицах есть ввод / вывод :
Он также показывает план функции сам по себе , который я включил только для полноты:
Теперь давайте посмотрим на фактический план, который в тысячи раз полезнее. Недостатком здесь, опять же, является то, что он имеет только ту информацию, которую SQL Server решает показать, поэтому он может отображать только те графические планы, которые предоставляет SQL Server. Это не та ситуация, когда кто-то решил не показывать вам что-то полезное; он просто ничего не знает об этом на основании предоставленного плана XML. В этом случае, как и в SSMS, вы можете видеть только план внешнего запроса, и это как если бы функция вообще не вызывалась :
Вкладка Table I / O также все еще зависит от выводаSTATISTICS IO
, который также игнорирует любые действия, выполняемые в вызове функции:
Однако PE получает весь стек вызовов за вас. Я иногда слышал, как люди спрашивают: «Пффф, когда мне когда-нибудь понадобится стек вызовов?» На самом деле вы можете разбить время, затраченное на ЦП и количество операций чтения (и, для TVF, количество произведенных строк) для каждого вызова функции :
К сожалению, у вас нет возможности соотнести ту информацию с какой таблицей (ями) поступает ввод-вывод (опять же, потому что SQL Server не предоставляет эту информацию), и он не помечен именем UDF (потому что он записывается как специальный оператор, а не сам вызов функции). Но то, что он позволяет вам увидеть, а Management Studio - нет, это то, чем является собака вашей UDF. Вам все еще нужно соединить несколько точек, но точек меньше, и они ближе друг к другу.
О Профилировщике
Наконец, я настоятельно рекомендую держаться подальше от Profiler, если только вы не хотите настраивать трассировку на стороне сервера, которую вы собираетесь сценарировать, а затем запускать вне области действия любого инструмента пользовательского интерфейса. Использование Profiler против производственной системы почти наверняка вызовет больше проблем, чем когда-либо решит . Если вы хотите получить эту информацию, пожалуйста, используйте трассировку на стороне сервера или расширенные события, и обязательно фильтруйте очень мудро. Даже без профилировщика трассировка может повлиять на ваш сервер, и получение showplans с помощью расширенных событий также не самая эффективная вещь в мире .