僅在使用 SESSION_CONTEXT 時在 Azure 中進行非並行計劃
我正在觀察本地電腦和 Azure SQL 上的查詢計劃之間的奇怪差異。我正在嘗試實現行級安全性,我從 SESSION_CONTEXT 讀取使用者標識符,然後在 TVF 中檢查使用者是否具有訪問權限。
在我的本地機器上 - SQL Server 2019 Developer edition,兼容級別為 150 的數據庫,查詢計劃符合預期。但是,當我在也是 150 兼容級別的 Azure DB 上執行它時,我只能獲得帶有
NonParallelPlanReason="NonParallelizableIntrinsicFunction"
. 我嘗試了一個超大規模數據庫以及彈性池中的一個數據庫,結果在兩個數據庫上都是相同的。您可以使用以下程式碼重現它:
CREATE TABLE Users ( UserIdentifier nvarchar(100) PRIMARY KEY CLUSTERED ) INSERT INTO Users (UserIdentifier) VALUES ('MyUserIdentifier') CREATE TABLE TableWithRLS ( Id int NOT NULL IDENTITY(1,1) PRIMARY KEY CLUSTERED, DataColumn nvarchar(100) NULL ) INSERT INTO TableWithRLS (DataColumn) SELECT TOP 10000000 A.[name] FROM sys.all_columns AS A CROSS JOIN sys.all_columns AS B CROSS JOIN sys.all_columns AS C CREATE OR ALTER FUNCTION CheckAccess (@userIdentifier varchar(100)) RETURNS TABLE WITH SCHEMABINDING AS RETURN SELECT TOP 1 1 AS HasAccess FROM dbo.Users WHERE UserIdentifier = @userIdentifier EXEC sp_set_session_context N'UserIdentifier', N'MyUserIdentifier', 1 -- This query gets always non-parallel query plan on Azure SELECT MAX(DataColumn) FROM TableWithRLS AS X CROSS APPLY CheckAccess(CAST(SESSION_CONTEXT(N'UserIdentifier') AS nvarchar(100)))
當我首先將會話上下文中的值選擇到變數中時,即使在 Azure 中它也會生成可並行化的查詢計劃。
DECLARE @userIdentifier AS nvarchar(100) = CAST(SESSION_CONTEXT(N'UserIdentifier') AS nvarchar(100)) SELECT MAX(DataColumn) FROM TableWithRLS AS X CROSS APPLY CheckAccess(@userIdentifier)
不幸的是,我不能這樣做(或者至少我不知道該怎麼做),因為我需要一個內聯 TVF。
Azure 的查詢計劃:https ://www.brentozar.com/pastetheplan/?id=ByxZm45e9
本地查詢計劃:https ://www.brentozar.com/pastetheplan/?id=BylHXV9lc
Azure 中的 SESSION_CONTEXT 實現有什麼不同可能導致這種情況嗎?或者有沒有人有任何其他想法可能是什麼問題?
Azure 中的 SESSION_CONTEXT 實現有什麼不同可能導致這種情況嗎?
是的。儘管 Azure SQL 數據庫和 SQL Server 是從一個通用程式碼庫建構的,但一個領先於另一個的情況並不少見。儘管微軟在過去幾年進行了行銷,但並不總是領先於 Azure 版本。
使用時禁止並行計劃是目前在 Azure 中啟用
SESSION_CONTEXT
的功能標誌 ( DisableSessionContextParallelPlan ),無法將其關閉。它可以在 SQL Server 上使用未記錄的跟踪標誌 11042 在查詢、會話、全域和啟動級別啟用。使用 Stack Overflow 展示數據庫(任何並行查詢都可以):
EXECUTE sys.sp_set_session_context @key = N'key', @value = 123, @read_only = 1; SELECT COUNT_BIG(*) FROM dbo.Badges AS B WHERE B.UserId = CONVERT(integer, SESSION_CONTEXT(N'Key')) OPTION (QUERYTRACEON 11042);
查詢是並行的,沒有 SQL Server 上的跟踪標誌。
這些選項通常添加到預覽功能中,作為對罕見錯誤情況或存在安全風險的響應。
SQL Server 2019 CU14 中發布了在並行計劃中使用時錯誤結果的錯誤修復。
SESSION_CONTEXT
我與 MS 取得了聯繫,並且在使用並行計劃時確實存在問題
SESSION_CONTEXT
,因此他們使用跟踪標誌禁用了它們。它已經修復,但跟踪標誌計劃在下一個全球版本中刪除,所以在幾個月內它應該有望重新啟用。