SQL Server:是否可以将UPDLOCK与非聚集索引一起使用?

时间:2017-04-12 15:52:04

标签: sql sql-server sql-server-2012 transactions locking

在我的数据库中需要锁定某一天的所有议程记录,所以我执行:

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子句过滤的记录不同。 在SO的帖子中,我读过我应该在议程日期添加一个索引,以便只锁定与where子句匹配的天数。这似乎不起作用,可能因为索引应该在我的议程表中聚集我已经有一个聚簇索引(prima键,它是一个计数器整数)。那么,还有其他选择吗?

1 个答案:

答案 0 :(得分:1)

以下三个选项可以获得select *所需的Key-Range Locking行为:

  1. day
  2. 上的聚集索引
  3. day
  4. 上的唯一索引
  5. 涵盖day
  6. 上的非聚集索引

    覆盖非聚集索引的示例:

    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