Как исправить проблему производительности скалярного значения пользовательской функции в SQL Server 2005? - PullRequest
2 голосов
/ 01 декабря 2010

Пользовательская функция используется в хранимой процедуре. Пользовательская функция возвращает скалярное значение. Следующая логика, используемая в пользовательской функции

CREATE  FUNCTION [dbo].[udf_Test] ( @Code varchar(10),  )  
  RETURNS bit AS    
BEGIN 
  DECLARE @bFlag bit  

  SELECT @bFlag = COUNT(id)  
    FROM tbL1  
   WHERE Code = @Code  

  IF  @bFlag = 0   
  BEGIN  
    SELECT @bFlag = COUNT(id)  
      FROM tbl2
     WHERE LTRIM(RTRIM(Code)) = @Code  
  END  

  IF @bFlag = 0   
  BEGIN  
    SELECT @bFlag = COUNT(id)  
      FROM tbl3  
     WHERE LTRIM(RTRIM(Code)) = @Code  
  END  

  IF @bFlag = 0   
  BEGIN  
    SELECT @bFlag = COUNT(id)  
      FROM tbl4
     WHERE LTRIM(RTRIM(Code)) = @Code  
  END

RETURN @bFlag 

Какой правильный способ улучшить производительность в вышеупомянутой пользовательской функции?

Ответы [ 2 ]

8 голосов
/ 01 декабря 2010

Лучший способ улучшить производительность - полностью отказаться от UDF.

Одна непосредственная вещь, которая приходит мне в голову, заключается в том, что

LTRIM(RTRIM(Code)) = @Code

не может быть sargable, поэтому каждый вызов (т. Е. каждая строка , возвращаемая в вашем внешнем запросе) может привести к увеличениюдо 4 сканирований таблицы.

Если вы замените логику в UDF выражением CASE, встроенным в запрос, вы вполне можете получить намного превосходящий план выполнения .Даже если вы не сможете сделать предикат доступным по крайней мере, это позволит оптимизатору исследовать различные стратегии объединения, такие как хэш-соединение, вместо принудительного повторного сканирования тех же таблиц.

2 голосов
/ 01 декабря 2010

В его нынешнем виде ...

WHERE LTRIM(RTRIM(Code)) = @Code; использование ltrim (rtrim (.. предотвратит использование индекса.

В идеале у вас должен быть результат ltrim(rtrim(Code)) в качестве индексированного столбца, чтобы можно было использовать индекс в предложении WHERE. Это ускорит процесс.

Установка @bFlag = COUNT(id), когда @bFlag - это int, а COUNT(id) int - не так уж приятно! Вам действительно следует использовать CASE WHEN COUNT(id) > 0 THEN 1 ELSE 0 END или иное.

Однако более эффективно использовать подход IF EXISTS, поскольку это приведет к короткому замыканию, как только будет найдена одна строка, соответствующая вашим критериям.

т.е.

DECLARE @bFlag bit 
SELECT @bFlag = 0

IF EXISTS (SELECT 'x' FROM tbl1 where Code= @Code ) SELECT @bFlag = 1
-- etc.
RETURN @bFlag 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...