1

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

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

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

我编写了一个存储过程来获取表名并使用 sp_Executesql 对传入的表名运行 UPDATE STATISTICS。存储过程和表都归 dbo 所有。我收到一条错误消息,提示“找不到对象“表”,因为它不存在或您没有权限。” 如果我将表上的更改授予用户,那么它可以正常工作,但我想避免这样做。我认为如果表和存储过程由同一所有者拥有,那么用户的权限将被忽略。

是否可以在没有更改表权限的情况下以某种方式运行 UPDATE STATISTICS?

4

2 回答 2

6

如果您使用sp_executesql. 除非您使该过程在其他人的上下文中执行。而不是选择另一个用户,我宁愿创建一个没有登录的用户。因此,假设您有一个名为 的表dbo.farb,该用户foobarblat不能ALTERDENY不是必需的,但它确实证明了这一点):

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

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

CREATE USER SuperSecret WITHOUT LOGIN;
GO
GRANT ALTER ON dbo.farb TO SuperSecret;
GO

现在我们可以编写一个在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;

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

EXEC dbo.UpdateStats 'dbo.farb';
于 2012-06-15T02:34:43.770 回答
5

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

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

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

于 2012-06-15T17:31:16.913 回答