Есть ли способ улучшить производительность этой функции SQL? - PullRequest
2 голосов
/ 16 января 2012

У меня есть таблица, которая выглядит как

Event ID  Date       Instructor
1         1/1/2000    Person 1
1         1/1/2000    Person 2

Теперь я хочу вернуть эти данные, чтобы каждое событие находилось в одной строке, а все преподаватели были разделены на один столбец с тегом <br>, например 'Person 1 <br> Person 2'

.

В настоящее время я сделал это, используя функцию

CREATE FUNCTION fnReturnInstructorNamesAsHTML
(
    @EventID INT
)
RETURNS VARCHAR(max)
BEGIN

    DECLARE @Result VARCHAR(MAX)

    SELECT 
        @result = coalesce(@result + '<br>', '') + inst.InstructorName 
    FROM
        [OpsInstructorEventsView]   inst
    WHERE
        inst.EventID = @EventID

    RETURN @result


END

Тогда моя основная хранимая процедура вызывает ее как

   SELECT 
        ev.[BGcolour], 
        ev.[Event] AS name, 
        ev.[eventid] AS ID, 
        ev.[eventstart], 
        ev.[CourseType], 
        ev.[Type], 
        ev.[OtherType], 
        ev.[OtherTypeDesc], 
        ev.[eventend], 
        ev.[CourseNo], 
        ev.[Confirmed], 
        ev.[Cancelled], 
        ev.[DeviceID] AS resource_id, 
        ev.Crew, 
        ev.CompanyName , 
        ev.Notes,
        dbo.fnReturnInstructorNamesAsHTML(ev.EventID) as Names
    FROM 
        [OpsSimEventsView] ev
    JOIN
        [OpsInstructorEventsView]   inst
    ON
        ev.EventID = inst.EventID 

Это очень медленно, я смотрю 4 секунды на вызов в БД. Есть ли способ для меня улучшить производительность функции? Это довольно маленькая функция, поэтому я не уверен, что я могу сделать здесь, и я не мог найти способ включить COALESCE в SELECT основной процедуры.

Любая помощь будет очень признательна, спасибо.

Ответы [ 3 ]

1 голос
/ 16 января 2012

Вы можете попробовать что-то вроде этого.

SELECT 
    ev.[BGcolour], 
    ev.[Event] AS name, 
    ev.[eventid] AS ID, 
    ev.[eventstart], 
    ev.[CourseType], 
    ev.[Type], 
    ev.[OtherType], 
    ev.[OtherTypeDesc], 
    ev.[eventend], 
    ev.[CourseNo], 
    ev.[Confirmed], 
    ev.[Cancelled], 
    ev.[DeviceID] AS resource_id, 
    ev.Crew, 
    ev.CompanyName , 
    ev.Notes,
    STUFF((SELECT '<br>'+inst.InstructorName
           FROM [OpsInstructorEventsView]   inst
           WHERE ev.EventID = inst.EventID
           FOR XML PATH(''), TYPE).value('.', 'nvarchar(max)'), 1, 4, '') as Names
FROM 
    [OpsSimEventsView] ev

Не уверен, почему вы присоединились к OpsInstructorEventsView в основном запросе.Я удалил это здесь, но если вам нужно, вы можете просто добавить его снова.

0 голосов
/ 16 января 2012

Да, сделайте функцию INLINE Table-Valued SQL:

 CREATE FUNCTION fnReturnInstructorNamesAsHTML 
 (  @EventID INT  ) 
 RETURNS Table   
 As 
  Return

  SELECT  InstructorName + '<br>' result 
  FROM OpsInstructorEventsView
  WHERE EventID = @EventID 
  Go

Затем, в своем выражении SQL, используйте ее следующим образом

SELECT    ]Other stuff],
    (Select result from dbo.fnReturnInstructorNamesAsHTML(ev.EventID)) as Names   
FROM OpsSimEventsView ev   
   JOIN OpsInstructorEventsView inst   
     ON  ev.EventID = inst.EventID    

Я не совсем понимаю, какзапрос, который вы показываете в своем вопросе, объединяет данные из нескольких строк в одной строке результата, но проблема в том, что обычные пользовательские функции компилируются при использовании, при КАЖДОМ использовании, поэтому для каждой строки в выходном результате Query processopr должен перекомпилироватьснова UDF.Это НЕ верно для UDF с «табличным значением», так как его sql складывается во внешний sql перед его передачей в оптимизатор SQL (подсистему, которая генерирует план кэширования операторов), и поэтому UDF компилируется только один раз.

0 голосов
/ 16 января 2012

Несколько вещей, на которые стоит обратить внимание:

1) Излишние издержки на функции делают их дорогостоящими для вызова, особенно в операторе select запроса, который потенциально может возвращать тысячи строк.Он должен будет выполнить эту функцию для каждого из них.Попробуйте объединить поведение функции с вашей основной хранимой процедурой, чтобы SQL Server мог лучше использовать свой оптимизатор.

2) Поскольку вы объединяетесь по идентификатору события в обеих таблицах, убедитесь, что у вас есть индексна этих двух столбцах.Я ожидаю, что вы это сделаете, учитывая, что оба эти столбца являются первичными ключами, но обязательно.Индекс может иметь огромное значение.

3) Преобразуйте ваш объединенный вызов в его эквивалентные операторы case, чтобы устранить накладные расходы при вызове этой функции.

...