declare
@fromLocalTime TIME = '06:00:00',
@toLocalTime TIME = '06:59:59',
@runDate AS DATETIME2
SET @runDate = GETUTCDATE()
DECLARE @notificationCreatedFromDate AS DATETIME2 = (SELECT DATEADD(day, -1, @runDate))
SELECT
Col1,
Col2,
Col3,
...,
Global.UDF_ConvertDateUtcToTimeZone(@runDate, tz.TimeZone) AS 'UserLocalTime',
tz.TimeZone
FROM Notification tn
INNER JOIN Dilect d ON d.DilectID = tn.DilectID AND d.IsActive = 1
INNER JOIN NotificationType nt ON nt.NotificationTypeID = tn.NotificationTypeID AND nt.IsActive = 1
INNER JOIN Task t ON t.TaskID = tn.TaskID AND t.IsActive = 1 AND t.ApplicationID = @ApplicationID
INNER JOIN UserTimeZone userTz ON userTz.UserID = tn.UserID AND userTz.ClientId = t.ClientId
INNER JOIN Global.TimeZone tz ON tz.TimeZoneId = userTz.TimeZoneId AND tz.IsActive = 1
WHERE CAST (Global.UDF_ConvertDateUtcToTimeZone(@runDate, tz.TimeZone) AS TIME) BETWEEN @fromLocalTime AND @toLocalTime
AND tn.CompletedDate IS NULL
AND tn.IsActive = 1
AND d.CompletedDate IS NOT NULL
AND tn.Created_DT >= @notificationCreatedFromDate and tn.Created_DT <= @runDate
WHERE CAST (Global.UDF_ConvertDateUtcToTimeZone(@runDate, tz.TimeZone) AS TIME) BETWEEN @fromLocalTime AND @toLocalTime
我有這個以前寫的查詢,直到昨天都運行良好。突然,這個查詢需要很長時間才能執行(現在 10 分鐘 - 之前 10 秒)。我之前在列上添加了建議的索引。問題是由于上面代碼中突出顯示的行(WHERE 子句)。如果我保留該行代碼,則查詢需要 10 分鐘才能執行,如果洗掉它會在 10 秒內執行,并且都回傳300K記錄。我已經閱讀了幾篇關于 CAST 如何影響選擇陳述句的文章——但與場景無關。我還嘗試將除突出顯示的行之外的所有代碼移至外部查詢,并在 where 子句中給出突出顯示的查詢,但看不到性能有任何差異。
有人可以告訴我這行(WHERE 子句)有什么問題,并提出解決這個問題的建議。
uj5u.com熱心網友回復:
Global.UDF_ConvertDateUtcToTimeZone(@runDate, tz.TimeZone) AS 'UserLocalTime',
SQL Server 很難優化用戶定義的標量函式,通常必須為每一行呼叫該函式。如果函式本身本質上是低效的,那么您的問題就會成倍增加,并且隨著資料變大而不斷增加。微軟試圖在現代版本中解決這個問題,但有很多限制和限制,他們必須在幾乎每個累積更新中修復一些問題。
與其依靠引擎最終彌補這種低效率,更好的策略是從一開始就撰寫行內(而不是多陳述句!)表值函式。這導致將查詢邏輯折疊到外部查詢中,并為 SQL Server 提供更好的統計資訊和更多可供考慮的優化路徑。
假設您的標量函式如下所示:
CREATE FUNCTION dbo.DoAThingToOneRow(@i int)
RETURNS int
AS
BEGIN
RETURN (SELECT [output] = @i 1);
END
你這樣稱呼它:
SELECT [object_id],
[output] = dbo.DoAThingToOneRow([object_id])
FROM sys.all_objects;
將其更改為:
CREATE FUNCTION dbo.DoAThingToAllRows(@i int)
RETURNS TABLE WITH SCHEMABINDING
AS
RETURN (SELECT [output] = @i 1);
并這樣稱呼它:
SELECT o.[object_id],
f.[output]
FROM sys.all_objects AS o
CROSS APPLY dbo.DoAThingToAllRows(o.[object_id]) AS f;
- 示例db<>fiddle
我可以探討計劃和執行統計資料之間的差異,但您應該使用自己的函式自行執行此操作,以獲得更真實的比較。您可以檢查諸如sys.dm_exec_query_stats和之類的東西sys.dm_exec_function_stats。
- 閱讀更多:
- SCHEMABINDING 的好處
- 將標量 UDF 重構為行內 TVF 以提高性能
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/478966.html
