2017-04-12 229 views
1

在我的数据库需要锁定某一天的所有议程的记录,所以我执行:SQL Server:是否可以将UPDLOCK与非聚集索引一起使用?

BEGIN TRANSACTION T1 
select * 
from DBName.dbo.Agenda WITH (UPDLOCK) 
where day='2017-04-20' 
/* COMMIT TRANSACTION T1 */ 

然后,在此期间我已经试过

BEGIN TRANSACTION T2 
select * 
from DBName.dbo.Agenda WITH (UPDLOCK) 
where day='2017-04-18' 
COMMIT TRANSACTION T2 

反正事务T2被阻塞,直到T1已经完成,即使由where子句过滤的记录不同。 在这里的一篇文章中,我读过我应该在议程当天添加一个索引,以便只匹配where子句的日子被锁定。这似乎不起作用,也许是因为索引应该被聚集在我的议程表中,我已经有一个聚集索引(主键,它是一个计数器整数)。那么,还有其他的选择吗?

回答

1

这里有三个选项得到你想要的select *Key-Range Locking行为:在day

的上day

  • 覆盖非聚簇索引

    1. 簇索引day
    2. 唯一索引涵盖非聚集索引的示例:

      create table dbo.agenda (
          id int not null identity (1, 1) primary key clustered 
          , [day] date 
          , comment varchar(64) not null default newid() 
      ); 
      insert into dbo.agenda ([day]) values 
      ('20170417') ,('20170418') ,('20170419') ,('20170420') ,('20170421'),('20170422'); 
      
      create nonclustered index ix_agenda_day on dbo.agenda ([day]) include (id, comment); 
      

      然后在单独的会话中运行两个事务,并使用sp_WhoIsActive by Adam Machanic

      enter image description here


      如果你只选择[day]id, [day](因为聚集键包含在非聚集索引),那么你的非覆盖非聚集索引将提供你想要的行为,并使用锁键范围该指数。

      enter image description here

  • +0

    感谢您对我的回复SqlZim。这听起来非常有趣,我一到达办公室就会在明天早上尝试它。即使我读过你链接的文章,恐怕我对锁定范围和“覆盖非聚集索引”的理解也不甚了了。为什么需要现场“评论”?我会尝试阅读更多的文档,但我不是DBMS的高级专家...... –

    +0

    事实上,所有这些混乱都会出现,因为根据某些要求,每天只能创建数量有限的议程,因此一次只有一个用户(在执行INSERT INTO查询之前)可以知道当天现有议程的数量。这就是为什么我需要在做出决定时锁定记录......而UPDLOCK似乎是唯一适用于我的记录。我也尝试了SERIALIZABLE TRANSACTION LEVEL,根据文档,它应该锁定用SELECT QUERY读取的记录,但这不会发生。 –

    +1

    @LoryLory'comment'字段对于我的示例来说明'select *'和'select [date]'之间的区别是必需的。对于'select *',你需要在索引中包含()所有其他列。如果你选择[日期],那么你不需要包含所有其他列。 – SqlZim

    相关问题