為什麼我在家工作時會使用 tSQLt 獲得 PREEMPTIVE_OS_AUTHORIZATIONOPS?
我有一個包含 tSQLt 單元測試的 SSDT 項目。
在家工作時,我總是發現發布此內容並執行所有測試(來自部署後腳本)是有問題的(針對 localdb 和 SQL Server 開發人員版)。
發布無限期掛起,我最終不得不殺死視覺工作室。
等待類型是,等待這個(從)
PREEMPTIVE_OS_AUTHORIZATIONOPS
掛起的語句範例是sys.dm_exec_sql_text
(@r BIT OUTPUT) SELECT @r = CASE WHEN I.Version = I.ClrVersion THEN 1 ELSE 0 END FROM tSQLt.Info() AS I;
我也通過呼叫來重現這個
SELECT tSQLt.Private::Info()
這是一個簡單的方法
public static SqlString Info() { return (SqlString) Assembly.GetExecutingAssembly().GetName().Version.ToString(); }
我假設它正在嘗試聯繫域控制器以確認我具有某些權限或其他權限。我沒有使用其他 CLR 程序集得到這個,因此懷疑這可能與 TSQLT 不是
SAFE_ACCESS
程序集有關(權限集是EXTERNAL_ACCESS
)。任何人都知道這裡發生了什麼以及我如何解決這個問題並在不遇到這種情況的情況下與我公司的網路斷開連接?
如果您不打算一直連接到域,因為它是一個開發實例,請將 db 所有者從域帳戶更改為本地帳戶或 sql 帳戶。
查看這個關於這個主題的精彩部落格:
http://andreas-wolter.com/en/where-is-that-preemptive-wait-coming-from/
總結部落格文章:
- 將數據庫所有者作為域使用者會導致 kerberos 票證授予票證請求(即 sql 想要使用作為 db 所有者的域帳戶進行身份驗證,而 kerberos 有一個稱為票證授予票證的東西,它可以讓 sql 模擬數據庫所有者)
- 如果您的域控制器延遲較高(或在本例中出現連接問題),這些呼叫會很慢
- SQL 將呼叫記憶體 10 分鐘,因此這些呼叫可能會出現斷斷續續的情況
和
經過大量測試(可以在相關討論中找到詳細資訊),我們已經縮小了掛起發生所需的因素,但最終不是導致掛起本身的因素。
我們現在知道的:
未連接VPN時,完全沒有挂機。我懷疑這是由於作業系統意識到它無法訪問域控制器進行任何驗證,因此它回退到記憶體的憑據。
如果測試成功執行(即未連接到 VPN 時),則可以連接 VPN 並繼續執行測試。這表明正在記憶體 SQL Server 和/或作業系統級別的權限。我們還不清楚記憶體發生在哪裡,但我們至少能夠排除權限與載入的程序集一起記憶體(我們通過解除安裝應用程序域然後重新執行測試來做到這一點)連接了 VPN 並且它沒有掛起)。
一段時間後(或者現在看來,由於我們在測試中所處的位置),如果 VPN 仍然連接並且App Domain 已解除安裝,那麼再次嘗試執行測試將再次導致程序掛起。@Ed 的答案中發布的連結似乎證實了在測試中看到的大約 10 分鐘的記憶體超時。
當程序掛起時,是在一系列外部呼叫期間獲取 Windows 安全資訊(您可以看到 Martin 在討論中發布的堆棧跟踪:https ://chat.stackexchange.com/transcript/message/40428311#40428311 — 點擊“(查看全文)”連結,然後查找
sqllang.dll!FVerifyAssemblyPermsForSids
)當大會設置為
SAFE
:對 TVF 的初始呼叫
Info()
成功,因為沒有要檢查的權限。但是,tSQLt.Private_Init儲存過程總是嘗試將程序
tSQLtCLR
集標記為EXTERNAL_ACCESS
,在這種情況下(假設尚未安裝非對稱密鑰*)*:
- 如果
TRUSTWORTHY
是,則proc 中對procOFF
的呼叫失敗,並出現“未授權 EXTERNAL_ACCESS 或 UNSAFE …”錯誤,因為不是並且沒有非對稱密鑰。然而它並沒有掛起,因為這是一個不需要作業系統任何東西的元數據操作。這應該是對 的呼叫,這是上述步驟的前一步。Init``tSQLt.EnableExternalAccess``TRUSTWORTHY``ON``ISECManager::FIsAssemblyAuthorized``FVerifyAssemblyPermsForSids
- 如果
TRUSTWORTHY
是,則proc 中對procON
的呼叫掛起,因為:a)它通過了“授權”檢查,b)然後需要檢查作業系統級別的權限。因此,它掛在聲明上。Init``tSQLt.EnableExternalAccess``ALTER ASSEMBLY tSQLtCLR WITH PERMISSION_SET = EXTERNAL_ACCESS;
當大會設置為
EXTERNAL_ACCESS
:如果
TRUSTWORTHY
是OFF
,則Init
proc 中對Info()
TVF 的呼叫由於缺乏授權而失敗。這與我們在上面看到的問題是相同TRUSTWORTHY
的OFF
。錯誤消息是不同的,但這只是因為查詢位於TRY...CATCH
具有自定義錯誤消息的構造中(呼叫tSQLt.EnableExternalAccess
也在TRY...CATCH
構造中,但該呼叫不會覆蓋CATCH
塊中的錯誤消息)。如果
TRUSTWORTHY
是ON
,則Init
proc 中對Info()
TVF 的呼叫會掛起,因為它會到達作業系統以從域控制器獲取 SID 權限資訊。還有什麼要弄清楚的:
- 記憶體在哪裡進行,持續多長時間?我們一直在解除安裝應用程序域,並可能通過以下方式發布基於 SQL Server 的身份驗證記憶體:
DBCC FREESYSTEMCACHE('ALL') WITH MARK_IN_USE_FOR_REMOVAL;
. 然而,我們還沒有找到一個一致的、可重複的時間長度。到目前為止,它似乎是大約 9 分鐘。- 如果 VPN 已連接並且程序集已載入到記憶體中,並且一切正常,那麼掛起是否會再次發生?
- 如果數據庫有,這會發生
TRUSTWORTHY OFF
嗎?這可以通過等到掛起狀態再次出現,然後執行來測試EXEC tSQLt.InstallExternalAccessKey
。然後,設置TRUSTWORTHY OFF
並重試。擁有 Asymmetric Key 和基於簽名的 Login 肯定比依賴 更好
TRUSTWORTHY ON
,所以最好切換到它並不TRUSTWORTHY OFF
管它。 4. 最後:為什麼它會掛起?是否有任何其他程序掛在 SQL Server 之外?還是這是特定於 SQL Server 的問題?@Sean Gallardy(在討論中)建議:操作需要這麼長時間的原因似乎是聯繫 DC 和/或檢索您的資訊(組等)的問題。我的猜測是您所描述的網路不匹配,其中一個介面(網際網路)以某種方式被選擇來查找此資訊 - 這永遠不會完成。