SQL Оптимизация представления, используемого udf - PullRequest
0 голосов
/ 24 ноября 2011

База данных: SQL Server 2005

Я использую функцию, которая создает список через запятую, используя функцию COALESCE.

ALTER FUNCTION [dbo].[func_Codes](@CustID int, @GroupID int)
returns varchar(1000) as
BEGIN
    DECLARE @List varchar(1000)

    SELECT @List = COALESCE(@List + ',', '') + Code
    FROM dbo.vw_CustBillingInfo 
    WHERE dbo.vw_CustBillingInfo.CustID = @CustID
        AND dbo.vw_CustBillingInfo.GroupID = @GroupID

    RETURN @List
END

Представление, которое он вызывает, использует следующую настройку:

SELECT <columns>
FROM (SELECT <columns>
      FROM Customer
      INNER JOIN Codes ON dbo.GetRootCode(Customer.Code) = Codes.SpecialCode 
      OR (IsNumeric(Customer.Code) = 0 AND Substring(Customer.Code,2,3) = Codes.SpecialCode)

      UNION

      SELECT <columns>
      FROM Customer
      INNER JOIN Codes ON dbo.GetRootCode(Customer.Code2) = Codes.SpecialCode 
         OR (IsNumeric(Customer.Code2) = 0 AND Substring(Customer.Code2,2,3) = Codes.SpecialCode)

      UNION

      <Repeat a few more similar unions>

Скалярная функция dbo.GetRootCode(code) выполняет некоторые операции с подстрокой над столбцом, чтобы извлечь специальную часть varchar column.

Если я уберу запрос из представления, я смогу повысить производительность, создав временную таблицу и сохранив значения GetRootCode(Customer.Code), IsNumeric(Customer.Code), Substring(Customer.Code,2,3), и т. д. для каждого используемого кода.Это не самый лучший подход, но он показывает, что можно провести оптимизацию.Также представление все равно не может использовать временную таблицу.

Вместо функции создания списка, разделенного запятыми, я попробовал вариант xml, который видел несколько мест в сети.

STUFF((
    SELECT ','+Code FROM dbo.vw_CustBillingInfo WHERE dbo.vw_CustBillingInfo.CustID = C.CustID AND dbo.vw_CustBillingInfo.GroupID = C.GroupID FOR XML PATH('')
        ), 1, 1, '')

Однако, хотя это работало, производительность была довольно ужасной.Время выполнения запроса увеличилось на 20–30 секунд

. Это возвращает меня к попыткам оптимизировать представление напрямую для повышения производительности.Статистика ввода-вывода показывает, что первым выбором представления будет:

(20 row(s) affected)
Table 'Worktable'. Scan count 1, logical reads 42920, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Customer'. Scan count 1, logical reads 269, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
Table 'Codes'. Scan count 1, logical reads 2, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.

Для выполнения требуется более секунды.Добавьте это ко всем объединениям, и затем это представление вызывается дважды по пути выполнения, и время значительно увеличивается.

Я застрял на наилучшем способе оптимизации ВНУТРЕННЕГО СОЕДИНЕНИЯ представления, чтобы увеличитьскорость и уменьшить IO требуется.Любые предложения будут с благодарностью.

1 Ответ

1 голос
/ 24 ноября 2011

Вы используете ДВУХ несаргируемых JOIN условий на JOIN.

Таким образом, вы получаете как минимум сканирование таблицы на JOIN, возможно два в зависимости от вашей реализации.

Действительно короткий ответ:

  • Не JOIN в UDF
  • Не JOIN используйте другие функции (например, SUBSTRING).

Практически НЕТ СПОСОБА оптимизировать это. SQL не знает, какой будет выход, пока не запустит функцию, поэтому он запускает ее для каждой строки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...