Добавление критериев в процедуру приводит к снижению производительности

У меня есть функция fncDeptInfo. В настоящее время он возвращает около 1000 записей менее чем за секунду:

ALTER FUNCTION [dbo].[fncDeptInfo]()
RETURNS TABLE 
AS
RETURN 
(
    SELECT 
        tblContacts.Contact, 
        CASE tblContacts.Parent1
            WHEN 1900 THEN 0 
            WHEN 1901 THEN 1
            WHEN 1902 THEN 2
            WHEN 1903 THEN 3
            WHEN 1904 THEN 4
            WHEN 1905 THEN 5
            WHEN 1906 THEN 6
            ELSE NULL 
        END AS PRArea,
        DISTRICT.Contact AS DistrictID
    FROM 
        tblContacts 
    LEFT OUTER JOIN
        tblContacts AS DISTRICT ON tblContacts.Parent2 = DISTRICT.Contact 
    WHERE    
        (tblContacts.ContactType = 'Fire') AND
        (tblContacts.SubType = 'Dept')
)

У меня есть процедура, которая вызывает эту функцию ниже:

SELECT  
    fncDeptInfo.Contact, DEPTPAID.CurPaid, 
    fncDeptInfo.PRArea, fncDeptInfo.DistrictID              
FROM    
    fncDeptInfo() AS fncDeptInfo 
INNER JOIN
    (SELECT 
         v_Item.BillToContact AS Contact,
         SUM(CASE WHEN Expiration = @Date1 AND tblProgramCodes.FormatCode = 'Membership' THEN 1 ELSE 0 END) AS CurPaid
     FROM 
         v_Item 
     INNER JOIN
         tblProgramCodes ON v_Item.ProgramCodeID = tblProgramCodes.ProgramCode 
     GROUP BY 
         v_Item.BillToContact) DEPTPAID ON fncDeptInfo.Contact = DEPTPAID.Contact
WHERE 
    (fncDeptInfo.PRArea > 0) AND (fncDeptInfo.DistrictID > 0) 
ORDER BY 
    fncDeptInfo.Contact

v_Item это очень сложное представление, которое объединяет финансовые записи в разных таблицах. Возвращает более 300 000 строк. Процедура, как задумано, возвращается через 5 секунд.

Если я добавлю этот фрагмент, чтобы получить информацию о Chief в fncDeptInfo, процедура займет полторы минуты. Но fncDeptInfo сам по себе возвращается примерно через секунду:

LEFT OUTER JOIN fncEmployee(GETDATE(), 'Chief') AS CHIEF 
  ON tblContacts.Contact = CHIEF.Contact2 

Если я добавлю этот критерий к процедуре, то теперь это займет полторы минуты. Однако, если я удаляю fncDeptInfo из процедуры, он снова возвращается через 5 секунд:

WHERE CurPaid > 0

Я предполагаю, что представление как-то задействовано в обоих случаях и неоднократно вызывается. Может кто-нибудь предложить лучший способ сделать так, чтобы производительность не страдала?

1 ответ

Решение

Простым вариантом является выбор вашего представления во временную таблицу, что предотвращает повторный вызов представления. Что-то вроде

IF Object_ID ('tempdb..vitem_tmp') is not null DROP TABLE #vitem_tmp

SELECT *
INTO #vitem_tmp
FROM v_Item

[Your query, referencing #vitem_tmp instead of v_Item]
Другие вопросы по тегам