是否可以限制用户的最大磁盘使用量

SQL*_*IKE 7 sql-server

是否可以对用户(或用户组)在单个数据库中可以使用的物理磁盘空间量设置限制?例如,是否有某种方法可以将模式与文件组相关联,然后为文件组设置最大大小?实际的数据库上会有其他表,因此希望有其他不受限制的文件组。

Aar*_*and 10

如果您的用户在他们自己的架构中拥有创建权限,那么您可以设置一个 DDL 触发器来捕获发生在与您关联的文件组不同的文件组上的表创建。您无法阻止创建该表,但您可以将其回滚并返回错误消息。

首先,让我们向现有数据库添加一个文件组和一个最大大小的文件:

USE [master];
GO

ALTER DATABASE floob ADD FILEGROUP SomeUser;
GO

ALTER DATABASE floob ADD FILE 
(
  NAME = SomeUser, 
  FILENAME = 'C:\...wherever...\floob_SomeUser.mdf',
  MAXSIZE = 20MB -- your quota, this part is important!
) TO FILEGROUP SomeUser; -- this part is also important!
GO
Run Code Online (Sandbox Code Playgroud)

现在让我们创建一个架构和一个可以控制该架构的登录名:

CREATE SCHEMA SomeUser;
GO

CREATE LOGIN SomeUser WITH PASSWORD = 'foo', CHECK_POLICY = OFF;
GO

USE floob;
GO

CREATE USER SomeUser FROM LOGIN [SomeUser] WITH DEFAULT_SCHEMA = SomeUser;
GO

GRANT CONTROL ON SCHEMA::SomeUser TO dbo;
GRANT CREATE TABLE TO SomeUser;
GO
Run Code Online (Sandbox Code Playgroud)

首先,通过这些设置,该用户无法在 dbo 或除他们自己以外的任何其他架构中创建表,这意味着默认情况下他们只能在其有限的文件 [组] 上创建表。如果您以此用户身份连接到数据库 floob 并尝试在 dbo 中创建一个表:

CREATE TABLE dbo.foo(id INT);
Run Code Online (Sandbox Code Playgroud)

您收到此错误:

消息 2760,级别 16,状态 1,第 1 行
指定的架构名称“dbo”不存在或您无权使用它。

并且由于该用户的 default_schema,不指定 SomeUser 架构仍然会以在 SomeUser 中创建的表结束(尽管您确实应该在这里推动最佳实践,尤其是在这种情况下,并且在创建或引用对象时始终指定架构名称)。

现在我们可以创建一个像这样的触发器,它会在没有指定文件组的情况下回滚整个批处理:

CREATE TRIGGER EnsureFilegroup
ON DATABASE
FOR CREATE_TABLE
AS
BEGIN
  DECLARE @e XML = EVENTDATA();

  IF @e.value('(/EVENT_INSTANCE/SchemaName)[1]', 'NVARCHAR(128)') = N'SomeUser'
     AND NOT EXISTS (SELECT 1 FROM sys.indexes AS i INNER JOIN sys.data_spaces AS d
       ON i.data_space_id = d.data_space_id
       WHERE d.name = N'SomeUser'
       AND i.[object_id] = OBJECT_ID(
        QUOTENAME(@e.value('(/EVENT_INSTANCE/SchemaName)[1]',  'NVARCHAR(128)'))
        + '.' + QUOTENAME(@e.value('(/EVENT_INSTANCE/ObjectName)[1]',  'NVARCHAR(128)')))
       AND i.index_id IN (0,1))

  BEGIN
    RAISERROR('You must place your objects on the SomeUser filegroup.', 11, 1);
    ROLLBACK TRANSACTION;
  END
END
GO
Run Code Online (Sandbox Code Playgroud)

保持用户、模式和文件组名称相同特别方便,这样可以更容易地将其作为程序化。您可以首先检查正在使用的架构是否不是您的“无限制”架构之一,然后继续检查将架构名称与文件组名称进行比较。如果不匹配,则该用户有权访问错误的架构并尝试在错误的位置创建对象,并且将引发错误:

ALTER TRIGGER EnsureFilegroup
ON DATABASE
FOR CREATE_TABLE
AS
BEGIN
  DECLARE @e XML = EVENTDATA();

  IF @e.value('(/EVENT_INSTANCE/SchemaName)[1]', 'NVARCHAR(128)') <> N'dbo'
    -- or NOT IN (N'dbo', N'other unlimited schemas')
  BEGIN

    IF NOT EXISTS (SELECT 1 FROM sys.indexes AS i INNER JOIN sys.data_spaces AS d
       ON i.data_space_id = d.data_space_id
       WHERE d.name = @e.value('(/EVENT_INSTANCE/SchemaName)[1]', 'NVARCHAR(128)')
       AND i.[object_id] = OBJECT_ID(
        QUOTENAME(@e.value('(/EVENT_INSTANCE/SchemaName)[1]',  'NVARCHAR(128)'))
        + '.' + QUOTENAME(@e.value('(/EVENT_INSTANCE/ObjectName)[1]',  'NVARCHAR(128)')))
       AND i.index_id IN (0,1))
    BEGIN
      RAISERROR('You must place your objects on your own filegroup.', 11, 1);
      ROLLBACK TRANSACTION;
    END
  END
END
GO
Run Code Online (Sandbox Code Playgroud)

  • 好东西亚伦。非常好。 (2认同)