当调用用户没有ALTER TABLE时,从存储过程调用UPDATE STATISTICS

Mik*_*e B 1 sql-server stored-procedures sql-server-2008-r2

我有一个应用程序,允许用户上传大型数据文件,然后解析并将数据存储在SQL Server 2008 R2数据库中.

我想在导入数据的表上自动运行UPDATE STATISTICS,因为用户可以运行数据报告并且数据量非常大.

数据访问是通过存储过程完成的,用户对表没有权限,只对存储过程执行.

我编写了一个存储过程来获取一个表名,并使用sp_Executesql对传入的表名运行UPDATE STATISTICS.存储过程和表都归dbo所有.我收到一条错误,上面写着"无法找到对象"表"因为它不存在或您没有权限." 如果我在桌面上向用户授予alter,那么它可以正常工作,但我想避免这样做.我认为如果表和存储过程由同一所有者拥有,则忽略用户的权限.

没有alter table权限,是否可以以某种方式运行UPDATE STATISTICS?

Aar*_*and 6

如果使用,则不能忽略用户的权限sp_executesql.除非您在其他人的上下文中执行该过程.我宁愿创建一个没有登录的用户,而不是选择另一个用户.所以假设你有一个叫做dbo.farb用户foobarblat不能的表ALTER(DENY不是必需的,但它确实证明了这一点):

USE master;
GO
CREATE LOGIN foobarblat WITH PASSWORD = 'foobarblat', CHECK_POLICY = OFF;
GO
USE YourDatabase;
GO
CREATE USER foobarblat FROM LOGIN foobarblat;
GO
CREATE TABLE dbo.farb(id INT);
GO
DENY ALTER ON dbo.farb to foobarblat;
GO
Run Code Online (Sandbox Code Playgroud)

现在让我们创建一个隐藏用户 - 我们可以为这个用户提供世界上所有权限,因为没有人可以实际以这个用户身份登录,但是对于这个例子,我们只能ALTER在我们的表上授予权限:

CREATE USER SuperSecret WITHOUT LOGIN;
GO
GRANT ALTER ON dbo.farb TO SuperSecret;
GO
Run Code Online (Sandbox Code Playgroud)

现在我们可以编写一个在SuperSecret用户上下文中执行的存储过程,但可以通过以下方式执行foobarblat:

CREATE PROCEDURE dbo.UpdateStats
    @tablename NVARCHAR(511)
WITH EXECUTE AS 'SuperSecret'
AS
BEGIN
    DECLARE @sql NVARCHAR(MAX);
    SET @sql = N'UPDATE STATISTICS ' + @tablename;
    EXEC sp_executesql @sql;
END
GO
GRANT EXEC ON dbo.UpdateStats TO foobarblat;
Run Code Online (Sandbox Code Playgroud)

现在使用连接在一个新窗口中foobarblat- 你应该能够执行这个没问题:

EXEC dbo.UpdateStats 'dbo.farb';
Run Code Online (Sandbox Code Playgroud)


Ben*_*hul 5

除了Aaron Bertrand所说的,我还将添加另一个解决方案:模块签名.所需步骤(简而言之):

  • 创建证书
  • 将其导入SQL Server
  • 从证书创建登录
  • 从登录创建用户
  • 向用户授予权限(在本例中为alter table)
  • 使用证书对存储过程进行签名
  • 授予exec对存储过程的权限给任何需要运行它的人

我看到的优点是,当程序运行时,您将看到谁在实际运行它.缺点是对存储过程的任何更改都需要您重新签名(即签名不会在更改过程中持续存在)和一些初始设置.亚伦的方法具有相反的优势.