2013-10-11 94 views
0

SQL不是我最好的東西,但我一直在試圖優化這個存儲過程。它有多個標量值函數,我試圖改變爲表值函數,因爲我在很多地方讀過它,這是一種更有效的方法。現在我有他們,但不確定如何實現,或者如果我可能只是沒有正確創建它們。SELECT語句中的SQL表值函數

這是我打來的功能。

Alter FUNCTION [IsNotSenateActivityTableValue] 
(
    @ActivityCode int, 
    @BillId int, 
    @TextToDisplay varchar(max) 
) 
returns @T table(result varchar(max)) 
as 
begin 
DECLARE @result varchar(max); 
    declare @countcodes int; 


declare @ishousebill int; 

select @ishousebill = count(billid) 
from BillMaster 
where BillID = @BillID and Chamber = 'H' 

If (@ishousebill = 0) 
begin 


SELECT @countcodes = count([ActivityCode]) 
     FROM [HouseCoreData].[dbo].[ActivityCode] 
     where ActivityDescription not like '%(H)%' and ActivityType = 'S' 
     and [ActivityCode] = @ActivityCode 

if (@countcodes = 0) 
begin 
    set @result = 'test' 
    end 
    else 
    begin 
     set @result = 'test2' 
    end 
end 
else 
begin 
    set @result = @TextToDisplay 
end 
RETURN 

END 

這就是我想要這樣稱呼他們的方式。我希望能夠把他們放在最前面,但真正有用的東西是好的。

SELECT distinct  
     ActionDates.result as ActionDate 
     ,ActivityDescriptions.result as ActivityDescription   
    FROM BillWebReporting.vwBillDetailWithSubjectIndex as vw 
    left outer join [BillWebReporting].[HasHouseSummary] as HasSummary on vw.BillID = HasSummary.BillID 
    outer APPLY dbo.IsNotSenateActivityDateTableValue(ActivityCode,vw.BillID,[ActionDate]) ActionDates  
    OUTER APPLY dbo.IsNotSenateActivityTableValue(ActivityCode,vw.BillID,[ActivityDescription]) as ActivityDescriptions 
+0

標籤上寫着'mysql',但是這看起來很* *很像T-SQL和SQL Server 。 – RBarryYoung

+0

你的功能是否真的有效?你在哪裏插入@T?它只是意味着返回一行嗎? –

+1

此外,最有效的表值函數類型是一個內聯表值函數(它只有一個'RETURN(SELECT ...);'而沒有其他這些代碼位)。一個多語句表值函數,就像您要編寫的函數一樣,實際上很容易出現很多與您要避免的相同的性能問題。 –

回答

0

表值函數返回一個表,其中像任何其他表一樣,必須插入行。

而不是做set @result = .....的,這樣做:

INSERT INTO @T (result) VALUES (.....) 

編輯:作爲一個方面說明,我真的不明白這個函數爲表值的原因。你基本上返回一個的值。

+0

是的,這個問題回來了,照顧我看到一些評論。什麼是更好的方式來做到這一點。我剛剛開始研究用於加速標量值函數的替代方法。 –

+0

返回單個值意味着標量函數。使其表價值將是一個不必要的複雜 - 可能微不足道,授予,但仍然是不必要的。我不知道哪一個更快,但我猜想這種差異是微不足道的。性能問題應該針對在函數內部使用的其餘對象進行優化。 – geomagas

+2

除了爲了使其成爲'inline' UDF,它必須是表值而不是標量,並且內聯UDF在執行多次的情況下性能要高得多。 –

3

得到一個計數,看看是否至少有一行存在是非常昂貴的。您應該使用EXISTS,這可能會導致短路而不實現整個計數。

這是一種使用內聯表值函數而不是多語句表值函數的更高效方法。

ALTER FUNCTION dbo.[IsNotSenateActivityTableValue] -- always use schema prefix! 
(
    @ActivityCode int, 
    @BillId int, 
    @TextToDisplay varchar(max) 
) 
RETURNS TABLE 
AS 
    RETURN (SELECT result = CASE WHEN EXISTS 
    (SELECT 1 FROM dbo.BillMaster 
    WHERE BillID = @BillID AND Chamber = 'H' 
) THEN @TextToDisplay ELSE CASE WHEN EXISTS 
    (SELECT 1 FROM [HouseCoreData].[dbo].[ActivityCode] 
     where ActivityDescription not like '%(H)%' 
     and ActivityType = 'S' 
     and [ActivityCode] = @ActivityCode 
) THEN 'test2' ELSE 'test' END 
    END); 
GO 

當然這也可能只是一個標量UDF ...

ALTER FUNCTION dbo.[IsNotSenateActivityScalar] -- always use schema prefix! 
(
    @ActivityCode int, 
    @BillId int, 
    @TextToDisplay varchar(max) 
) 
RETURNS VARCHAR(MAX) 
AS 
BEGIN 
    DECLARE @result VARCHAR(MAX); 

    SELECT @result = CASE WHEN EXISTS 
    (SELECT 1 FROM dbo.BillMaster 
    WHERE BillID = @BillID AND Chamber = 'H' 
) THEN @TextToDisplay ELSE CASE WHEN EXISTS 
    (SELECT 1 FROM [HouseCoreData].[dbo].[ActivityCode] 
     where ActivityDescription not like '%(H)%' 
     and ActivityType = 'S' 
     and [ActivityCode] = @ActivityCode 
) THEN 'test2' ELSE 'test' END 
    END; 

    RETURN (@result); 
END 
GO 
+0

這是一個標量UDF,但我拿出來試圖加快性能。你認爲如果我在這個功能中嘗試了這個功能,它會提高性能,足以成爲可用的。 –

+0

我懷疑你的標量UDF或表值UDF的選擇會對性能產生明顯的影響 - 這可能是由於更大的打擊者 - 很差/沒有支持索引,不良統計信息,內存不足等等。當你運行這個查詢,生成一個實際的執行計劃,並查看是否有任何突出的內容(例如非常昂貴的掃描,缺少索引建議等)。 –

+0

在Sql Server中,使用內聯UDF的Aaron比多語句UDF快得多,並且在多次調用UDF的情況下(例如,對於嵌入的外部查詢的每一行,它可以是一次),它可以做出巨大的改變。這是不是在mySQL的情況? –

0

所有的UDF首先通常是非常不穩定的高性能。我對MySQL沒有把握,但在Sql Server中,UDF每次都會重新編譯(FOR EACH ROW OF OUTPUT),除了所謂的內聯 UDF,它只有一個select語句,它是摺疊到包含在...中的外部查詢的SQL中,因此只編譯一次。

的MySQL確實有inline table-valued functions,用它來代替......在SQL Server中,語法爲:

CREATE FUNCTION IsNotSenateActivityTableValue 
(
@ActivityCode int, 
@BillId int, 
@TextToDisplay varchar(max) 
) 
RETURNS TABLE 
AS 
RETURN 
(
Select case 
    When y.bilCnt + z.actCnt = 0 Then 'test' 
    when y.bilCnt = 0 then 'test2' 
    else @TextToDisplay end result 
From (Select Count(billId) bilCnt 
     From BillMaster 
     Where BillID = @BillID 
     And Chamber = 'H') y 
    Full Join 
    (Select count([ActivityCode]) actCnt 
     From [HouseCoreData].[dbo].[ActivityCode] 
     Where ActivityDescription not like '%(H)%' 
     And ActivityType = 'S' 
     And [ActivityCode] = @ActivityCode) z 

) 
GO