除了 SA 之外,谁能指出我需要的正确文档或其他权限来执行以下操作?
当我运行它时,我收到以下错误:
找不到对象“#test”,因为它不存在或您没有权限。
IF NOT EXISTS
(
SELECT
name
FROM sys.server_principals
WHERE
name = 'testlimiteduser'
)
BEGIN
CREATE LOGIN [testlimiteduser] WITH PASSWORD=N'apassword', DEFAULT_DATABASE=[tempdb], CHECK_EXPIRATION=OFF, CHECK_POLICY=OFF
END
IF NOT EXISTS
(
SELECT
name
FROM sys.database_principals
WHERE
name = 'testlimiteduser'
)
BEGIN
CREATE USER [testlimiteduser] FOR LOGIN [testlimiteduser] WITH DEFAULT_SCHEMA=[dbo]
END
IF NOT EXISTS
(
SELECT 1
FROM sys.database_principals AS p
WHERE
p.name like 'testlimiteduser_app'
)
BEGIN
CREATE ROLE testlimiteduser_app
GRANT EXECUTE TO testlimiteduser_app
ALTER ROLE [db_datareader] ADD MEMBER testlimiteduser_app
ALTER ROLE [db_datawriter] ADD MEMBER testlimiteduser_app
ALTER ROLE testlimiteduser_app ADD MEMBER [testlimiteduser]
ALTER ROLE db_owner ADD MEMBER testlimiteduser -- https://learn.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-updateusage-transact-sql?view=sql-server-2017 says db_owner or SA
END
GO
exec as user='testlimiteduser'
drop table if exists #test
create table #test (id int )
exec('UPDATE STATISTICS #test WITH ROWCOUNT = 1000000')
select * from #test
revert;
检查https://learn.microsoft.com/en-us/sql/t-sql/database-console-commands/dbcc-updateusage-transact-sql?view=sql-server-2017中的文档说 db_owner 或 SA 是很好,但它甚至没有出现在我的测试中 db_owner 工作。
建立一个帐户
db_owner
,即使是[tempdb]
,仍然是有风险的。幸运的是,没有必要为了实现目标而这样做。您可以简单地使用模块签名来允许驻留在[tempdb]
使用db_owner
数据库角色的存储过程:最初设定
这只是让我们进入与问题中提供的代码相同的状态(减去
testlimiteduser_app
角色,这对于这个目标是不必要的)。基本设置
我们需要一个可以签名的模块(即席 SQL 不起作用),但我们还没有签名。
在这里,我们:
测试 1
请注意:最好使用
EXECUTE AS LOGIN
,不仅AS USER
在LOGIN
应用程序确实连接到 SQL Server 时会发生什么更准确,而且这样做USER
会增加可能会扭曲行为/测试结果的限制。模块签名设置
[master]
测试 2
我们对存储过程进行了签名并将其与登录名相关联,但我们尚未为该登录名授予必要的权限,因此结果是相同的。
最终设置:为登录或用户分配权限
这被保留为一个单独的步骤,只是为了非常清楚地表明确实是模块签名让这个工作。你有两个选择(只选一个):
将现有的基于证书的登录添加到
sysadmin
实例级角色或者:
从基于证书的登录创建一个用户
tempdb
,然后将新用户添加到db_owner
数据库级角色测试 3
结论
选项之间的主要区别是:
tempdb
(需要在每次启动 SQL Server 服务时创建)sysadmin
权限更强大(不完全是“最小特权”)db_owner
比 更包含sysadmin
tempdb
(需要在每次启动 SQL Server 服务时创建)和 db_owner`之间的差异
sysadmin
很小,即使在这里甚至不相关,因为使用这些权限中的任何一个可以完成的唯一事情是存储过程中的代码所做的事情(这是模块签名的主要好处之一:它是高度颗粒化)。tempdb
因此,在实际层面上,在每次启动 SQL Server 服务时创建用户并将其添加到其中的复杂性db_owner
(这需要在中创建存储过程master
,将其标记为“启动过程”,并启用实例级配置选项“扫描启动过程”)比登录更糟糕sysadmin
。如果需要额外权限的数据库是用户数据库,那么我可能会选择选项 2,即使只是为了使其与预期用途更匹配,而不是真正关心
sysadmin
vsdb_owner
。有关应用模块签名所采取步骤的详细说明,请参阅我的帖子:
无需将高级权限授予任何人即可安全轻松地使用高级权限:服务器级
有关模块签名的更多信息,请参阅我的帖子:
请,请,请停止使用模拟、可信和跨数据库所有权链接
您必须
exec('UPDATE STATISTICS #test WITH ROWCOUNT = 1000000')
在 tempdb 数据库中运行。基本上,临时表存在于 tempdb 中,而不存在于其他中。
呃,看来我错了。答案很简单:用户在 tempdb 数据库中缺乏执行此 update statistics 命令的权限
在 tempdb 数据库中创建临时表,默认情况下权限是有限的。
有四种类型的表:
GO
批处理分隔符处或脚本末尾进行清理的表值得注意的是 Temp 对象可以通过 引用
tempdb..#tablename
,尽管在普通语句中显式使用 tempdb 名称会被忽略,因为所有临时表都是在模式中Tempdb
和dbo
模式中创建的注意它们都在 tempdb 数据库中。yourstatement 失败的原因仅仅是由于 tempdb 中存在 #temp 表,并且您可能没有在 tempdb 中授予用户执行更新的权限。
通常,您只需要它来授予对表的更改,尽管我发现临时表有点不同并且可能需要更高的权限。但由于这是同一个会话,只需执行以下操作:
现在您甚至不需要向用户授予提升的权限并满足您的问题。
我做了一些额外的挖掘并发现了以下内容:临时表上的任何查询都可以正常工作,它的 WITH ROWCOUNT 导致了问题。标准的 UPDATE STATISTICS 也可以顺利进行。
我浏览了 MSDN 文档,但没有找到与 UPDATE STATISTICS 相结合的 SET ROWCOUNT 权限的明确注释 - 经过一些推测和测试后,我发现DBCC UPDATEUSAGE的文档要求数据库中包含 sysadmin 或 db_owner桌子。
如果将此添加到我的示例中,则代码有效:
不幸的是,我的原始代码没有说明它在 tempdb 之外的另一个数据库中运行,但这是一个隐含的假设,如果你忽略,整个脚本都可以工作(因为他们现在有 tempdb db_owner。)