2

У меня есть таблица, которая выглядит что-то вродеЕсть ли способ улучшить производительность этой функции SQL?

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 основной процедуры.

Любая помощь была бы действительно оценена, спасибо.

+0

Конкатенация строк (и строковые функции в целом) не является чем-то, что SQL когда-либо будет делать очень быстро. SQL оптимизирован для основанной на наборе логики, а не для итеративной рекурсии. – JNK

+1

@Purplegoldfish: простой способ повысить производительность - это удалить соединение с '[OpsInstructorEventsView]' из основного запроса, так как вы в настоящее время не используете ни одно из полей из него. –

+0

@MarkBannister Спасибо, я, должно быть, пропустил это, я оставил его, немного поиграв, пытаясь сделать это всего за один проход. – Purplegoldfish

ответ

1

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

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

Спасибо, это приносит производительность примерно до 1 секунды для 260 рядов, поэтому ее большое улучшение по сравнению с тем, что у меня было – Purplegoldfish

0

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

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

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

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

+0

'COALESCE' ** IS ** - оператор case в отношении оптимизатора. Subbing это добавит еще несколько символов в запрос. – JNK

+0

Это правда, однако, мое намерение заключалось в том, чтобы удалить накладные расходы для вызова самой функции, а не для изменения ее работы. При вызове функций в предложении select всегда будут какие-то накладные расходы, однако минимальные. Это может быть или не иметь значения. –

0

Да делают его INLINE табличное 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  

Я не совсем ясно, как запрос вы показать в вашем вопросе - объединение данных из нескольких строк в одну строку результата, но проблема в том, что обычные UDF скомпилированы при использовании при КАЖДОМ использовании, поэтому для каждой строки в вашем выходном результате процессу Processor необходимо повторно переписать UDF , Это НЕ ИСТИНА для ULF с встроенным табличным значением, поскольку он sql складывается во внешний sql, прежде чем он передается оптимизатору SQL (подсистема, которая генерирует план кэша операторов), и поэтому UDF только компилируется один раз.

+0

Функция, которую я вызывал, возвращала только одно значение, содержащее конкатенированные данные, содержащие все Имена для указанного идентификатора события, однако, когда я конвертирую его для использования предложенного метода, я все же получаю только 1 строку для имени, которая является данными, которые я начинаю с перед использованием функции :( – Purplegoldfish

Смежные вопросы