为什么我在家工作时会使用 tSQLt 获得 PREEMPTIVE_OS_AUTHORIZATIONOPS?

Mar*_*ith 6 sql-server wait-types sql-clr tsqlt

我有一个包含 tSQLt 单元测试的 SSDT 项目。

在家工作时,我总是发现发布此内容并运行所有测试(来自部署后脚本)是有问题的(针对 localdb 和 SQL Server 开发人员版)。

发布无限期挂起,我最终不得不杀死 Visual Studio。

等待类型是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; 
Run Code Online (Sandbox Code Playgroud)

我也通过调用重现这个

SELECT tSQLt.Private::Info()
Run Code Online (Sandbox Code Playgroud)

这是一个简单的方法

public static SqlString Info()
{
  return (SqlString) Assembly.GetExecutingAssembly().GetName().Version.ToString();
}
Run Code Online (Sandbox Code Playgroud)

我假设它正在尝试联系域控制器以建立我有一些权限或其他权限。我在其他 CLR 程序集上没有得到这个,因此怀疑这可能与 TSQLT 不是SAFE_ACCESS程序集有关(权限集是EXTERNAL_ACCESS)。

任何人都知道这里发生了什么以及我如何解决此问题并在与公司网络断开连接的情况下工作而不会遇到此问题?

Ed *_*ott 5

如果您不打算一直连接到域,因为它是一个开发实例,请将 db 所有者从域帐户更改为本地帐户或 sql 帐户。

查看这个关于这个主题的很棒的博客:

http://andreas-wolter.com/en/where-is-that-preemptive-wait-coming-from/

总结博客文章:

  • 将 db 所有者作为域用户会导致 kerberos 票证授予票证请求(即 sql 想要使用作为 db 所有者的域帐户进行身份验证,而 kerberos 有一个叫做票证授予票证的东西,它可以让 sql 模拟数据库所有者)
  • 如果您的域控制器有高延迟(或连接问题,如本例),这些调用将很慢
  • SQL 将调用缓存 10 分钟,因此这些调用可能会出现断断续续的情况

编辑


Sol*_*zky 3

经过大量测试(详细信息可以在相关讨论中找到),我们已经缩小了发生悬挂所需的因素范围,但没有最终确定导致悬挂本身的原因。

我们现在知道的是:

  1. 连接VPN时,根本不存在挂起的情况。我怀疑这是由于操作系统意识到它无法访问域控制器进行任何验证,因此它回退到缓存的凭据。
  2. 如果测试已成功运行(即连接到 VPN 时),则可以连接 VPN 并继续运行测试。这表明正在缓存 SQL Server 和/或操作系统级别的权限。我们还不清楚缓存发生在哪里,但我们至少能够排除权限是与加载的程序集一起缓存的(我们通过卸载应用程序域然后重新运行测试来做到这一点)连接 VPN 并且它没有挂起)。
  3. After some amount of time (or so it seems right now due to where we got in the testing), if the VPN is still connected and the App Domain is unloaded, then attempting to run a test again will again cause the process to hang. The link posted in @Ed's answer seems to confirm the roughly 10-minute cache timeout that was seen in testing.
  4. When the process hangs, it is during a series of external calls to get Windows security info (you can see the stack trace that Martin posted in the discussion at: https://chat.stackexchange.com/transcript/message/40428311#40428311 — click the "(see full text)" link and then look for sqllang.dll!FVerifyAssemblyPermsForSids)
  5. When the Assembly is set to SAFE:
    1. The initial call to the Info() TVF succeeds as there are no permissions to check.
    2. But, the tSQLt.Private_Init stored procedure always attempts to mark the tSQLtCLR Assembly as EXTERNAL_ACCESS, in which case (assuming that the Asymmetric Key has not been installed):
      1. If TRUSTWORTHY is OFF then the call in the Init proc to the tSQLt.EnableExternalAccess proc fails with the "unauthorized for EXTERNAL_ACCESS or UNSAFE..." error because TRUSTWORTHY is not ON AND there is no Asymmetric Key. Yet it does not hang because that is a meta-data operation that doesn't need anything from the OS. This should be the call to ISECManager::FIsAssemblyAuthorized, which is one step before the FVerifyAssemblyPermsForSids step that was noted above.
      2. 如果TRUSTWORTHY是,则proc 中对 proc 的ON调用将挂起,因为:a)它通过了“授权”检查,b)然后需要检查操作系统级别的权限。因此,它取决于声明。InittSQLt.EnableExternalAccessALTER ASSEMBLY tSQLtCLR WITH PERMISSION_SET = EXTERNAL_ACCESS;
  6. 当装配设置为EXTERNAL_ACCESS
    1. 如果TRUSTWORTHY是,则过程中对TVF 的OFF调用由于缺乏授权而失败。这与我们上面看到的问题相同。错误消息不同,但这只是由于查询位于具有自定义错误消息的构造中(对的调用也在构造内,但该调用不会覆盖块中的错误消息)。InitInfo()TRUSTWORTHYOFFTRY...CATCHtSQLt.EnableExternalAccessTRY...CATCHCATCH
    2. 如果TRUSTWORTHY是,那么当TVFON联系操作系统以从域控制器获取 SID 权限信息时,过程中对 TVF 的调用将挂起。InitInfo()

还剩下什么需要弄清楚:

  1. 缓存发生在哪里以及持续多长时间?我们已经卸载了应用程序域,并可能通过以下方式发布基于 SQL Server 的身份验证缓存:DBCC FREESYSTEMCACHE('ALL') WITH MARK_IN_USE_FOR_REMOVAL;。然而,我们尚未找到一致的、可重复的时间长度。到目前为止,时间似乎约为 9 分钟。
  2. 如果 VPN 已连接且程序集已加载到内存中,并且一切正常,那么挂起是否会再次发生?
  3. 如果数据库有的话,这种情况会发生吗TRUSTWORTHY OFF?可以通过等待挂起状态再次发生然后运行来测试这一点EXEC tSQLt.InstallExternalAccessKey。然后,设置TRUSTWORTHY OFF并重试。
    拥有非对称密钥和基于签名的登录肯定比依赖更好TRUSTWORTHY ON,因此最好切换到非对称密钥和基于签名的登录,并且无论如何TRUSTWORTHY OFF
  4. 最后:为什么它会挂起?SQL Server 之外是否还有其他进程挂起?或者这是 SQL Server 特有的问题?@Sean Gallardy(在讨论中)建议:

    操作花费这么长时间的原因似乎是联系 DC 和/或检索您的信息(群组等)的问题。我的猜测是,您所描述的网络不匹配,其中以某种方式选择一个接口(互联网)来查找此信息 - 这永远不会完成。