SQL Server最佳化標量函式改寫內聯表值函式

宅慕思_發表於2019-11-28

問題SQL:

SELECT TOP 1001 ha.HuntApplicationID ,
           ha.PartyNumber ,
           mht.Name AS MasterHuntTypeName ,
           htly.LicenseYear ,
           lStatus.[Status] AS DrawTicketStatus ,
           isnull(dbo.udf_GetHuntApplicationPartyCount(ha.HuntApplicationID), 0) AS MemberCount ,
           count( won.DrawTicketLicenseID) AS DrawnMemberCount ,
           won.drawticketid ,
           dt.PreDrawNonResidentMemberCount AS NRMemberCount ,
           dbo.udf_GetAvgPreferencePoints(dt.DrawTicketID) AS PreferencePointAverage ,
           CASE
               WHEN ha.Quantity > 1 THEN NULL
               ELSE dt.PreDrawRandomNumber
           END AS PreDrawRandomNumber ,
           dsm.Name AS DrawSelectionMethodName ,
           dt.DrawnSequence ,
           dt.PreferencePointRank ,
           dt.DrawID ,
           dt.RandomRank
FROM dbo.HuntApplication ha
JOIN dbo.HuntTypeLicenseYear htly ON ha.HuntTypeLicenseYearID = htly.HuntTypeLicenseYearID
JOIN dbo.MasterHuntType mht ON htly.MasterHuntTypeID = mht.MasterHuntTypeID
LEFT JOIN dbo.HuntApplicationLicense hal ON ha.HuntApplicationID = hal.HuntApplicationID
LEFT JOIN dbo.DrawTicket dt ON ha.HuntApplicationID = dt.HuntApplicationID
LEFT JOIN dbo.DrawTicketLicense won ON dt.DrawTicketID = won.DrawTicketID
AND won.WasDrawn = 1
LEFT JOIN dbo.DrawSelectionMethod dsm ON dt.DrawSelectionMethodID = dsm.DrawSelectionMethodID
LEFT JOIN dbo.StatusCode lStatus ON dt.StatusCodeID = lStatus.StatusCodeID
JOIN dbo.DrawTicketHuntChoice dthc ON dt.DrawTicketID = dthc.DrawTicketID
CROSS APPLY dbo.tvf_GetHuntApplicationPartyCount(ha.HuntApplicationID) hapc
CROSS APPLY dbo.tvf_GetAvgPreferencePoints(dt.DrawTicketID) app
WHERE 1 = 1
  AND htly.MasterHuntTypeID = @iMasterHuntTypeID
  AND htly.LicenseYear = @iLicenseYear
  AND dt.StatusCodeID = @iDrawTicketStatusCodeID
  AND dthc.WasDrawn = @iHuntChoiceWasDrawn
GROUP BY ha.HuntApplicationID,
         ha.PartyNumber,
         mht.[Name],
         htly.LicenseYear,
         lStatus.[Status],
         isnull(dbo.udf_GetHuntApplicationPartyCount(ha.HuntApplicationID), 0),
         won.DrawTicketID,
         dt.PreDrawNonResidentMemberCount,
         dbo.udf_GetAvgPreferencePoints(dt.DrawTicketID),
         CASE
             WHEN ha.Quantity > 1 THEN NULL
             ELSE dt.PreDrawRandomNumber
         END,
         dsm.[Name],
         dt.DrawnSequence,
         dt.PreferencePointRank,
         dt.DrawID,
         dt.RandomRank
ORDER BY htly.LicenseYear DESC,
         mht.Name,
         lStatus.[Status],
         dt.DrawID,
         PreferencePointAverage DESC,
         PreDrawRandomNumber,
         ha.PartyNumber

靜態函式:

CREATE FUNCTION [dbo].[udf_GetAvgPreferencePoints]
(@DrawTicketID INT)
RETURNS NUMERIC (18, 3)
AS
BEGIN
    RETURN
	(
		SELECT TOP 1
				CONVERT(DECIMAL, dt.PreDrawPreferencePointTotal) / NULLIF(CONVERT(DECIMAL, dt.PreDrawMemberCount),0)
		FROM dbo.DrawTicket dt
			WHERE dt.DrawTicketID = @DrawTicketID
	)
END

執行時間40s

這是典型可以進行靜態函式改寫內聯表值函式的sql:

改寫後:

SELECT TOP 1001 ha.HuntApplicationID ,
           ha.PartyNumber ,
           mht.Name AS MasterHuntTypeName ,
           htly.LicenseYear ,
           lStatus.[Status] AS DrawTicketStatus ,
           --isnull(dbo.udf_GetHuntApplicationPartyCount(ha.HuntApplicationID), 0) AS MemberCount ,
		   isnull(hapc.MemberCount, 0) AS MemberCount,
           count( won.DrawTicketLicenseID) AS DrawnMemberCount ,
           won.drawticketid ,
           dt.PreDrawNonResidentMemberCount AS NRMemberCount ,
           --dbo.udf_GetAvgPreferencePoints(dt.DrawTicketID) AS PreferencePointAverage ,
		   app.PreferencePointAverage PreferencePointAverage,
           CASE
               WHEN ha.Quantity > 1 THEN NULL
               ELSE dt.PreDrawRandomNumber
           END AS PreDrawRandomNumber ,
           dsm.Name AS DrawSelectionMethodName ,
           dt.DrawnSequence ,
           dt.PreferencePointRank ,
           dt.DrawID ,
           dt.RandomRank
FROM dbo.HuntApplication ha
JOIN dbo.HuntTypeLicenseYear htly ON ha.HuntTypeLicenseYearID = htly.HuntTypeLicenseYearID
JOIN dbo.MasterHuntType mht ON htly.MasterHuntTypeID = mht.MasterHuntTypeID
LEFT JOIN dbo.HuntApplicationLicense hal ON ha.HuntApplicationID = hal.HuntApplicationID
LEFT JOIN dbo.DrawTicket dt ON ha.HuntApplicationID = dt.HuntApplicationID
LEFT JOIN dbo.DrawTicketLicense won ON dt.DrawTicketID = won.DrawTicketID
AND won.WasDrawn = 1
LEFT JOIN dbo.DrawSelectionMethod dsm ON dt.DrawSelectionMethodID = dsm.DrawSelectionMethodID
LEFT JOIN dbo.StatusCode lStatus ON dt.StatusCodeID = lStatus.StatusCodeID
JOIN dbo.DrawTicketHuntChoice dthc ON dt.DrawTicketID = dthc.DrawTicketID
CROSS APPLY dbo.tvf_GetHuntApplicationPartyCount(ha.HuntApplicationID) hapc
CROSS APPLY dbo.tvf_GetAvgPreferencePoints(dt.DrawTicketID) app
WHERE 1 = 1
  AND htly.MasterHuntTypeID = @iMasterHuntTypeID
  AND htly.LicenseYear = @iLicenseYear
  AND dt.StatusCodeID = @iDrawTicketStatusCodeID
  AND dthc.WasDrawn = @iHuntChoiceWasDrawn
GROUP BY ha.HuntApplicationID,
         ha.PartyNumber,
         mht.[Name],
         htly.LicenseYear,
         lStatus.[Status],
         --isnull(dbo.udf_GetHuntApplicationPartyCount(ha.HuntApplicationID), 0),
		 isnull(hapc.MemberCount, 0),
         won.DrawTicketID,
         dt.PreDrawNonResidentMemberCount,
         --dbo.udf_GetAvgPreferencePoints(dt.DrawTicketID),
		 app.PreferencePointAverage,
         CASE
             WHEN ha.Quantity > 1 THEN NULL
             ELSE dt.PreDrawRandomNumber
         END,
         dsm.[Name],
         dt.DrawnSequence,
         dt.PreferencePointRank,
         dt.DrawID,
         dt.RandomRank
ORDER BY htly.LicenseYear DESC,
         mht.Name,
         lStatus.[Status],
         dt.DrawID,
         PreferencePointAverage DESC,
         PreDrawRandomNumber,
         ha.PartyNumber

對應的表值函式:

CREATE FUNCTION [dbo].[tvf_GetAvgPreferencePoints]
(@DrawTicketID INT)
RETURNS TABLE WITH SCHEMABINDING
AS
RETURN
(
	SELECT TOP 1
			CONVERT(DECIMAL, dt.PreDrawPreferencePointTotal) / NULLIF(CONVERT(DECIMAL, dt.PreDrawMemberCount),0) as PreferencePointAverage
	FROM dbo.DrawTicket dt
		WHERE dt.DrawTicketID = @DrawTicketID
)
GO

改寫後執行時間從40s降低到16s,對於傾斜列的最佳化速度更為明顯

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/69950462/viewspace-2666110/,如需轉載,請註明出處,否則將追究法律責任。

相關文章