我有几个用户在我的管理下共享 MS SQL Server 2017。他们不应该看到(甚至不知道)该服务器上的其他用户及其数据。每个用户都有自己的数据库。他们可以对他们的数据库做任何他们想做的事情。
我正在使用 SQL Server 的Partial Containment
功能将用户锁定到位。登录名是在数据库中创建的。这很有效,因为他们不会以这种方式看到其他用户帐户或数据库。数据库登录名被添加到我使用以下命令创建的数据库角色中:
USE dbname
CREATE ROLE dbrole
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE TABLE, CREATE VIEW, ALTER ANY SCHEMA TO dbrole
DENY EXECUTE TO dbrole
Run Code Online (Sandbox Code Playgroud)
我刚刚创建了一个 db 登录帐户,并将其添加到所述角色中。用户没有其他权限(我知道)。
剩下的唯一问题是 SSMS 仍然能够浏览服务器的文件系统。如果我右键单击数据库并选择Tasks -> Restore -> Database
,然后选择Device: -> [...]
并添加文件。这允许 SSMS 浏览服务器的文件系统,我想否认这一点。用户实际上不能恢复数据库,但他可以浏览文件系统。
这里的这个问题表明 SSMS 正在使用存储过程xp_fixeddrives
,xp_dirtree
并且xp_fileexist
. 但是,当以具有该组权限的用户身份执行时,这些存储过程返回空结果。我读过这是当用户不是 sysadmin 角色的成员时的行为。这已经让我有点困惑,因为我明确拒绝对 dbrole 执行 EXECUTE,但用户仍然可以执行存储过程。但是,通过 SSMS 浏览文件系统时,它仍然不是空的。
SSMS 从哪里获取文件系统信息,如何防止这种情况发生?
编辑:我也刚刚注意到 SSMS 能够检索所有数据库的服务器上存在的所有数据库备份的列表。同样,我不知道它如何获取这些信息以及如何防止它。
我们的应用程序时不时地(大约每周一次)遇到死锁。
罪魁祸首似乎是带有两个选择的查询。其中之一是出于性能原因填充临时表,另一个是具有许多连接的相对复杂的选择,以返回具有许多详细信息的所有约会的列表。我看到的关于第二个选择的唯一可能特别的地方是它包含一个自连接。二选查询始终是 SQL Server 死锁事件报告的一部分。
另一个查询是对同一个表的简单 DML 查询(插入或更新),尽管这并不总是相同的 DML 查询。这两个查询都以标准READ COMMITTED
隔离方式运行,而不是在显式事务中运行。
这两个查询大致如下(我已缩短它们以进行澄清)
DECLARE @futureAppointments TABLE(clientId int, StartDate date)
INSERT INTO @futureAppointments SELECT clientId, StartDate FROM Appointments where StartDate >= @startDate
SELECT *, (SELECT COUNT(*) FROM @futureAppointments fa WHERE fa.clientId = a.clientId AND fa.StartDate > a.StartDate)
FROM Appointments a
join b on a.fk_b = b.id
join c on a.fk_c = c.id
join Appointments d on c.somefield = d.anotherfield
WHERE a.StartDate >= @startDate AND a.StartDate <= @endDate
Run Code Online (Sandbox Code Playgroud)
UPDATE Appointments SET …
Run Code Online (Sandbox Code Playgroud) 对于非sys.columns
.sys.indexes
sys.tables
db_owner
要重现,请在 Linux 上使用 SQL Server 2022(我使用的是 16.0.4035,这是撰写本文时的最新版本)并执行以下命令。它创建一个虚拟数据库,其中包含 500 个表,每个表有 10 列,这样sys.columns
该数据库就会获取大约 5000 条记录。如果您手头的数据库总数超过 1000 列,则可以跳过创建虚拟数据库。
CREATE DATABASE SLOWSYSTABLES
GO
USE SLOWSYSTABLES
DECLARE @i int
DECLARE @createTable nvarchar(max)
SET @i = 0
WHILE (@i < 500)
BEGIN
SET @createTable = 'CREATE TABLE dummy_' + CAST(@i as nvarchar) + '(Col1 int not null identity(1,1) primary key, Col2 int, Col3 int, Col4 int, Col5 int, Col6 int, Col7 int, Col8 int, Col9 int, Col10 int)' …
Run Code Online (Sandbox Code Playgroud)