Я использую SQL Server 2008R2. Я написал следующий табличный UDF, который принимает либо скалярные значения того или иного, либо обоих в качестве параметров и возвращает таблицу с идентификатором столбцов, этим и этим. Я вижу ужасную производительность, когда вызываю эту функцию изнутри сложного запроса, но не когда я вызываю ее в простых запросах. Я хотел бы знать, есть ли у кого-нибудь какие-либо идеи о том, что я делаю, что замедляет ход событий. Определение функции следующее:
CREATE function dbo.fn_getThisThat (@this nvarchar(255), @that nvarchar(255))
RETURNS TABLE
RETURN
SELECT These.this, Those.that, COALESCE(These.ID, Those.ID) as ID
FROM
(
SELECT col1 as ‘this’, value1, value2, ID
FROM (
SELECT t1.col1, t1.col2, t1.col3, t2.col1
FROM t1
JOIN t2
ON t1.col1 = t2.col1
WHERE t2.col2 = ‘this’
AND t1.col1 in (‘value1’, ‘value2’)
) SOURCE
PIVOT (
MAX(t1.col3) FOR t1.col1 in (value1, value2)
) AS pvt
) These
JOIN
(
SELECT t1.col1, t1.col2, t2.col1, t3.ID
FROM t3
JOIN t1
ON t3.col1 = t1.col1
JOIN t2
ON t2.col1 = t1.col1
WHERE t3.col3 = ‘value3’
AND t1.col3 = ‘value1’
AND t2.col3 = ‘value2’
) Those
WHERE that = @that
OR this = @this
Следующий оператор обрабатывается очень быстро (<1 сек) при передаче скалярных параметров: </p>
SELECT * FROM dbo.fn_getThisThat(scalarValue, null)
Или в относительно простом запросе, например:
SELECT t1.col1, t1.col2, fn.This
FROM t1
CROSS APPLY dbo.fn_getThisThat(t1.col3, null)
… но он запаздывает (от времени обработки ~ 1 секунды до ~ 2: 30 секунд) при вызове в более сложном запросе, как этот (в псевдокоде: дайте мне знать, если информации недостаточно):
DECLARE @table (a, b, c)
INSERT @table (a, b, c)
SELECT (values)
SELECT t1.c1, t1.c2, t1.c3
FROM
(
SELECT a.c1, COUNT(fn.That) as c2, COUNT(a.c2) as c3
FROM a
JOIN b ON (join terms)
CROSS APPLY dbo.fn_getThisThat(a.c2, null) fn
WHERE a.c1 IN (SELECT a FROM @table)
GROUP BY a.c1
) t1
У кого-нибудь есть предложения относительно того, что я делаю, чтобы убить скорость во втором запросе? Я изменил функцию так, чтобы она принимала массив, а не скалярные параметры, но это исключило мою возможность перекрестного применения (в последнем фрагменте кода). Насколько я могу судить по анализатору запросов, снижение производительности связано с перекрестным применением моей функции. Я думал, что не столкнусь с RBAR, так как мой UDF не был многократным, но, возможно, я ужасно неправ ...?
EDIT:
Еще одна вещь: план выполнения запроса показывает, что сама функция вносит только 2% в пакет; более крупный запрос дает 98%, но большая часть его стоимости - поиск индекса и сканирование таблицы, а не параллелизм. Это заставило меня задуматься о том, что, возможно, вызов функции связан не столько с медлительностью запроса, сколько с отсутствием индексов в некоторых из задействованных таблиц (к сожалению, у меня нет большого контроля над добавлением индексы.). Я выполнил запрос без вызова функции, и сканирование таблицы и поиск индекса по-прежнему показывают высокий уровень, но запрос завершается примерно за 8 секунд. Итак, мы вернулись к функции ...?