2013-06-13 2 views
0

У меня есть хранимая процедура, которая занимает очень много времени, потому что у меня есть 2 вызова функций, которые вызывают перед PIVOT, что означает, что он вызывает функции 5 раз для каждой записи, а не один раз для каждой записи , Как я могу переписать мой запрос так, чтобы 2 вызова функций в конце запроса выполнялись после Pivot, а не раньше?Вызов SQL-функций после PIVOT

Вот запрос

CREATE TABLE #Temp 
(
ServiceRecordID INT, 
LocationStd VARCHAR(1000), 
AreaServedStd VARCHAR(1000), 
RegionalLimited BIT, 
Region VARCHAR(255), 
Visible BIT 
) 

DECLARE @RegionCount INT 

SELECT @RegionCount = COUNT(RegionID) FROM Regions WHERE SiteID = @SiteID AND RegionID % 100 != 0 

INSERT INTO #Temp 
SELECT TOP (@RegionCount * 100) SR.ServiceRecordID, SR.LocationStd, SR.AreaServedStd, SR.RegionalLimited, R.Region, 
     CASE WHEN (ISNULL(R_SR.RegionID,0) = 0 AND ISNULL(R_SR_Serv.RegionID,0) = 0) THEN 0 ELSE 1 END AS Visible 
FROM ServiceRecord SR 
INNER JOIN Sites S ON SR.SiteID = S.SiteID 
INNER JOIN Regions R ON R.SiteID = S.SiteID 
LEFT OUTER JOIN lkup_Region_ServiceRecord R_SR ON R_SR.RegionID = R.RegionID AND R_SR.ServiceRecordID = SR.ServiceRecordID 
LEFT OUTER JOIN lkup_Region_ServiceRecord_Serv R_SR_Serv ON R_SR_Serv.RegionID = R.RegionID AND R_SR_Serv.ServiceRecordID = SR.ServiceRecordID AND SR.RegionalLimited = 0 
WHERE SR.SiteID = @SiteID 
AND R.RegionID % 100 != 0 
ORDER BY SR.ServiceRecordID 

DECLARE @RegionList varchar(2000),@SQL varchar(max) 
SELECT @RegionList = STUFF((SELECT DISTINCT ',[' + Region + ']' FROM #Temp ORDER BY ',[' + Region + ']' FOR XML PATH('')),1,1,'') 

SET @SQL='SELECT * FROM 
(SELECT ServiceRecordID, 
dbo.fn_ServiceRecordGetServiceName(ServiceRecordID,'''') AS ServiceName, 
LocationStd, 
AreaServedStd, 
RegionalLimited, 
Region As Region, 
dbo.fn_GetOtherRegionalSitesForServiceRecord(ServiceRecordID) AS OtherSites, 
CAST(Visible AS INT) AS Visible FROM #Temp) B PIVOT(MAX(Visible) FOR Region IN (' + @RegionList + ')) A' 

EXEC(@SQL) 
+0

Да, вы должны иметь возможность заменить 'select *' фактическими именами столбцов, и вы можете использовать функцию для столбцов. – Taryn

+0

Упрощение: 'CASE WHEN R_SR.RegionID <> 0 И R_SR_Serv.RegionID <> 0 THEN 1 ELSE 0 END AS Visible' – ErikE

+0

спасибо bluefeet, не уверен, что я следую. У меня есть столбцы, которые выбираются индивидуально уже, не так ли? –

ответ

0

Перемещение вызовов функций после PIVOT:

SET @SQL=' 
SELECT 
    A.*, 
    N.ServiceName, 
    S.OtherSites 
FROM 
    (
     SELECT 
     ServiceRecordID, 
     LocationStd, 
     AreaServedStd, 
     RegionalLimited, 
     Region, 
     CAST(Visible AS INT) AS Visible 
     FROM #Temp 
    ) B 
    PIVOT(MAX(Visible) FOR Region IN (' + @RegionList + ')) A 
    OUTER APPLY (
     SELECT dbo.fn_ServiceRecordGetServiceName(A.ServiceRecordID,'''') 
    ) N (ServiceName) 
    OUTER APPLY (
     SELECT dbo.fn_GetOtherRegionalSitesForServiceRecord(A.ServiceRecordID) 
    ) S (OtherSites); 
'; 

Или просто положить их в наружной SELECT:

SET @SQL=' 
SELECT 
    A.*, 
    ServiceName = dbo.fn_ServiceRecordGetServiceName(A.ServiceRecordID,''''), 
    OtherSites = dbo.fn_GetOtherRegionalSitesForServiceRecord(A.ServiceRecordID) 
FROM 
    (
     SELECT 
     ServiceRecordID, 
     LocationStd, 
     AreaServedStd, 
     RegionalLimited, 
     Region, 
     CAST(Visible AS INT) AS Visible 
     FROM #Temp 
    ) B 
    PIVOT(MAX(Visible) FOR Region IN (' + @RegionList + ')) A 
'; 

Если возможно, вы можете конвертировать эти функции, которые должны быть таблично -значными rowset-возвращающимися, состоящими из одного оператора SELECT, вы можете получить огромный улучшение производительности.

CREATE FUNCTION dbo.fn_ServiceRecordGetServiceName2(
    @ServiceRecordID itn 
) 
RETURNS TABLE 
AS 
RETURN (-- single select statement 
    SELECT ServiceName = Blah 
    FROM dbo.Gorp 
    WHERE Gunk = 'Ralph' 
); 

Тогда

OUTER APPLY dbo.fn_ServiceRecordGetServiceName(ServiceRecordID,'''') N 

И N.ServiceName возвращает значение (ы).

Кроме того, неправильно скопировать квадратные скобки для преобразования значений данных в действительные sysname с. Вы должны использовать функцию QuoteName. Это будет гарантировать вашу систему не ломается, независимо от того, какие безумные значение вводится 13 лет с этого момента (думаю 'Taiwan [North]'):

STUFF((SELECT DISTINCT ',' + QuoteName(Region) FROM #Temp ... 

Примечание:

Так как вы сказали, что это для отображения на веб-странице , вам даже не нужно делать поворот на сервере. Вместо этого верните два набора строк для клиента, один с данными Сайта, и один с данными столбца для Регионов. Вам потребуется необходимо пройти через каждую строку в строке Region, чтобы узнать все регионы, но это можно сделать очень быстро. Наконец, скорректируйте свой программный код для перехода по строкам региона, если это необходимо для каждого соответствующего сайта, и создайте свой вывод.

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

P.S. Даже динамический SQL легче справиться, когда вы его хорошо отформатируете. :)

+0

wow спасибо тонну! Это сработало и сократило время на 300% и более! Обе функции возвращают значения Varchar (max) в формате, который мне нужен, на веб-странице. Как я могу правильно отобразить их, если они вернутся в табличном формате набора строк? –

+0

Он будет работать точно так же.Разница в том, что функция table-value возвращает набор строк, а не значение. Я показал вам, как с этим справиться с отдельной линией «OUTER APPLY» выше. – ErikE

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