为什么SQL Server 2008在长事务INSERT上阻止了SELECT?

ste*_*mac 17 sql-server sql-server-2008

我们正在尝试建立一个仅定期插入新记录的事务表.

这个简单的表要求我们不断添加新记录.此表中的事务量预计会非常高,并且可能会定期批量导入事务(> 1000),这可能需要几秒钟才能完成.

然后,我们从这些数据中执行一组select语句,将不同的列分组以返回所需的值.

从我们的初始测试中,我们发现了一个与SQL Server相关的瓶颈,它在INSERTS事务的中间阻塞了我们的SELECT.

下面是一个简单的示例,可用于说明问题.

- 简单的数据库表

create table LOCK_TEST (
LOCK_TEST_ID int identity ,
AMOUNT int);
Run Code Online (Sandbox Code Playgroud)

- 在1个查询窗口中运行此命令

begin tran
insert into LOCK_TEST (AMOUNT) values (1);
WAITFOR DELAY '00:00:15' ---- 15 Second Delay
insert into LOCK_TEST (AMOUNT) values (1);
commit
Run Code Online (Sandbox Code Playgroud)

- 在查询2中并行运行

select SUM(AMOUNT)
from LOCK_TEST;
Run Code Online (Sandbox Code Playgroud)

我希望查询2直接返回,0直到查询1完成,然后显示2.我们永远不希望看到从第二个查询返回1.

我们看到的答案与select语句中的WITH(NOLOCK)有关.但这违反了交易边界,返回的信息可能属于财务性质,我们不希望在查询中看到任何未提交的详细信息.

我的问题似乎是在INSERT方面...
为什么INSERT阻止SELECT语句,即使它没有修改任何现有数据?

奖励积分问题: 这是SQL Server的"功能",还是我们会在其他数据库版本上找到它?

更新 我现在有时间找到一个本地oracle数据库并运行相同的简单测试.这个测试通过我的预期.

即我可以根据需要经常运行查询,并且它将返回null,直到第一个事务提交,然后返回2.

有没有办法让SQL Server像这样工作?还是我们需要迁移到Oracle?

Nic*_*ias 12

此锁定行为是SQL Server的一项功能.使用2005及更高版本,您可以使用行级版本控制(默认情况下在Oracle上使用)来实现相同的结果而不会阻止您的选择.这会给tempdb带来额外的压力,因为tempdb会维护行级版本控制,因此请确保适应这种情况.要使SQL按照您希望的方式运行,请运行以下命令:

ALTER DATABASE MyDatabase
SET ALLOW_SNAPSHOT_ISOLATION ON

ALTER DATABASE MyDatabase
SET READ_COMMITTED_SNAPSHOT ON
Run Code Online (Sandbox Code Playgroud)