Как я могу оптимизировать эту ужасно неэффективную пользовательскую функцию в SQL Server 08 - PullRequest
1 голос
/ 16 апреля 2009

Есть ли способ оптимизировать этот ужасный неэффективный UDF в SQL Server 08. Я довольно новичок в UDF и особенно смотрю на них для оптимизации.

UPDATE: Должен ли я отправлять столбец в функцию, подобную этой, если я хочу выполнить ее для каждой строки и каждого столбца в запросе? Есть ли лучший способ сделать это?

Спасибо

** @value (float) и @fieldname (varchar (40)) являются входными параметрами **

BEGIN
  DECLARE @UT integer, @FRM integer, @TO integer, @FACTOR float

  select @UT =  [UF_UT_ID] FROM dbo.UNIT_FIELDS where [UF_FIELD]=@fieldName
  select @FRM = [UT_UN_ID_INTERNAL_UNITS] from dbo.UNIT_TYPES where [UT_ID]=@UT
  select @TO = [UT_UN_ID_DISPLAY_UNITS] from dbo.UNIT_TYPES where [UT_ID]=@UT
  select @FACTOR = [UC_SLOPE] from dbo.UNIT_CONVERSIONS where [UC_UN_ID_UNIT_FROM]=@FRM and [UC_UN_ID_UNIT_TO]=@TO

  -- Return the result of the function dbo.
  RETURN @FACTOR*@value
END

Ответы [ 7 ]

3 голосов
/ 16 апреля 2009

Если вы можете объединить три таблицы на основе отношений PK / FK, вы можете свести запрос к одному выбору. Если нет, то единственной очевидной оптимизацией является назначение @FRM и @TO в одном операторе выбора:

select @FRM = [UT_UN_ID_INTERNAL_UNITS], @TO = [UT_UN_ID_DISPLAY_UNITS] from dbo.UNIT_TYPES where [UT_ID]=@UT
2 голосов
/ 16 апреля 2009

Классический кандидат на встроенную табличную функцию ...

Что-то вроде:

ALTER FUNCTION fnName(@value float, @fieldName VARCHAR(100))
RETURNS TABLE 
AS
RETURN 
(
    SELECT @value * 
        (SELECT conv.[UC_SLOPE] from dbo.UNIT_CONVERSIONS conv
        JOIN dbo.UNIT_TYPES UT_UN_ID_INTERNAL_UNITS ON where [UC_UN_ID_UNIT_FROM]=UT_UN_ID_INTERNAL_UNITS.[UT_ID]
        JOIN dbo.UNIT_TYPES UT_UN_ID_DISPLAY_UNITS ON where [UC_UN_ID_UNIT_TO]=UT_UN_ID_DISPLAY_UNITS.[UT_ID]
        JOIN dbo.UNIT_FIELDS fields ON (UT_UN_ID_INTERNAL_UNITS.[UT_ID] = fields.[UF_UT_ID]) AND (UT_UN_ID_DISPLAY_UNITS.[UT_ID] = fields.[UF_UT_ID])
        WHERE ([UF_FIELD]=@fieldName)
        )
)
1 голос
/ 16 апреля 2009

Шаг 1 будет запускать каждый выбор в отдельности и видеть узкое место.

0 голосов
/ 16 апреля 2009

Вы можете попробовать это как все один запрос:

--Decalre Factor var
DECLARE @FACTOR float

SELECT @FACTOR = [UC_SLOPE] 
FROM dbo.UNIT_CONVERSIONS uc
--Join the Unit Types table to Unit Conversions on the old From & To types
INNER JOIN dbo.UNIT_TYPES ut ON
    ut.[UT_UN_ID_DISPLAY_UNITS] = uc.[UC_UN_ID_UNIT_TO]
    AND ut.[UT_UN_ID_INTERNAL_UNITS] = uc.[UC_UN_ID_UNIT_FROM]
--Join the Unit Files on the Unit Types
INNER JOIN dbo.UNIT_FIELDS uf ON
    uf.[UF_UT_ID] = ut.[UT_ID]
WHERE uf.[UF_FIELD]=@fieldName

-- Return the result of the function dbo.
RETURN @FACTOR*@value
0 голосов
/ 16 апреля 2009
BEGIN
  DECLARE @FACTOR float

    select @factor = UC.UC_SLOPE
      from dbo.UNIT_CONVERSIONS UC,
           dbo.UNIT_TYPES       UT,
           dbo.UNIT_FIELDS      UF
      where UF.UF_FIELD=@fieldName
        and UT.UT_ID = UF.UF_UT_ID
        and UC.UC_UN_ID_UNIT_FROM = UT.UT_UN_ID_INTERNAL_UNITS
        and UC.UC_UN_ID_UNIT_TO = UT.UT_UN_ID_DISPLAY_UNITS


  -- Return the result of the function dbo.
  RETURN @FACTOR*@value
END
0 голосов
/ 16 апреля 2009

Это необходимо переписать, используя JOIN:

SELECT  c.UC_SLOPE * @value
FROM    unit_fields f
JOIN    unit_types t
ON      t.UT_ID = f.UF_UT_ID
JOIN    unit_conversions c
ON      c.UC_UN_ID_UNIT_FROM = t.UT_UN_ID_INTERNAL_UNITS
        AND c.UC_UN_ID_UNIT_TO = t.UT_UN_ID_DISPLAY_UNITS
WHERE   f.UF_FIELD = @field_name
0 голосов
/ 16 апреля 2009

Одна маленькая вещь, которую вы можете сделать:

 select @FRM = [UT_UN_ID_INTERNAL_UNITS] from dbo.UNIT_TYPES where [UT_ID]=@UT  
 select @TO = [UT_UN_ID_DISPLAY_UNITS] from dbo.UNIT_TYPES where [UT_ID]=@UT 

Если я правильно прочитал, это было бы так же, как:

 select @TO = [UT_UN_ID_DISPLAY_UNITS],
        @FRM = [UT_UN_ID_INTERNAL_UNITS] 

 from dbo.UNIT_TYPES where [UT_ID]=@UT 

Зачем запускать выбор дважды для одной и той же записи?

...