选项(QUERYTRACEON 9481),动态 SQL 和 DBCC TRACEON 错误

问题描述 投票:0回答:2

我的处境有点奇怪... a) 我们正在将所有 SQL Server 实例升级到 2017 年。 b) 不少受影响的数据库正在使用旧版兼容性级别/基数估计器。 c) 我们希望拥有当前(2017)CL 上的所有数据库并使用最新的 CE。

计划是在单个语句级别使用“OPTION(QUERYTRACEON 9481)”来处理与新 CE 不兼容的查询。不是作为永久修复,而是作为克服困难的一种手段(重写每个受影响的程序根本超出了当前项目的范围)。

切入主题...这似乎按预期工作,除非存储过程使用动态 SQL 并且由非 SA 用户执行。这当然是有道理的。只要在过程范围内执行“OPTION(QUERYTRACEON 9481)”,所有权链接就会提供执行基础 DBCC TRACEON 命令所需的权限。然而,动态 SQL 的使用本质上将代码视为 AD-HOC SQL,并在用户自己的安全上下文下执行...这不是 SA,因此无权执行 DBCC TRACEON;

简短或重写查询或赋予应用程序服务帐户SA角色,有人有可用的解决方案吗?

提前谢谢您,

杰森

sql-server sql-server-2017
2个回答
2
投票

问题:

...然而,动态 SQL 的使用本质上将代码视为 AD-HOC SQL,并在用户自己的安全上下文下执行...这不是 SA,因此无权执行 DBCC TRACEON;

解决方案:

Kimberly Tripp 在她在 sqlskills.com 上的帖子中进行了精彩的解释:
“在逐个查询(或会话)的基础上设置 CE TraceFlags”

  1. 在 msdb 数据库上创建一个存储过程,允许在没有系统管理员权限的情况下设置所需的跟踪标志。
    (当然,系统管理员负责设置允许的跟踪标志值的列表)。

  2. 通过调用此存储过程来包装任何有问题的语句(动态 SQL、即席查询或过程调用),并更改执行的会话跟踪标志。
    这允许具有较低权限的用户更改基数估计器以执行有问题的语句。

用法示例:

EXEC msdb.dbo.msdbSetTraceFlag 9481, 1; 
GO  

Problematic STATEMENT or PROCEDURE   

EXEC msdb.dbo.msdbSetTraceFlag 9481, 0;  -- don't remember to turn it back off!    
GO

存储过程代码:

USE msdb;
GO

CREATE PROCEDURE msdbSetTraceFlag
    (@TraceFlag int,
     @OnOff bit = 0)
WITH EXECUTE AS OWNER
AS
DECLARE @OnOffStr char(1) = @OnOff;
-- Sysadmins can add supported trace flags and then use this
-- from their applications
IF @TraceFlag NOT IN (
              9481 -- LegacyCE if database is compat mode 120 or higher
            , 2312 -- NewCE if database compat mode 110 or lower
                     )
     BEGIN
         RAISERROR('The Trace Flag supplied is not supported. Please contact your system administrator to determine inclusion of this trace flag: %i.', 16, 1, @TraceFlag);
         RETURN
     END
ELSE
     BEGIN
         DECLARE @ExecStr nvarchar(100);
         IF @OnOff = 1
             SELECT @ExecStr = N'DBCC TRACEON(' + CONVERT(nvarchar(4), @TraceFlag) + N')';
         ELSE
             SELECT @ExecStr = N'DBCC TRACEOFF(' + CONVERT(nvarchar(4), @TraceFlag) + N')';
         -- SELECT (@ExecStr)
         EXEC(@ExecStr)
         -- RAISERROR (N'TraceFlag: %i has been set to:%s (1 = ON, 0 = OFF).', 10, 1, @TraceFlag, @OnOffStr);
     END;
GO

GRANT EXECUTE ON msdbSetTraceFlag TO PUBLIC --or to a specific set of users;
GO

注意: 此存储过程是在 msdb 中创建的,而不是在 master 上创建的,因为“可信”先决条件是 msdb 的默认值。


0
投票

-- 不要记得将其关闭!

是“——别忘了把它关掉!” ?

© www.soinside.com 2019 - 2024. All rights reserved.