如何让 SQL 插入和/或更新不锁定 MS SQL Server 上的整个表

Joh*_*ehl 15 sql-server locking

DB 工作的新手,所以感谢您对基本问题的耐心。我在本地机器上运行 SQL Server 2014,我有一个小表和一个基本的客户端应用程序来测试不同的方法。我在INSERT INTOandUPDATE语句中都得到了一个表锁。客户端是具有以下代码的 ASP.NET 应用程序:

OleDbConnection cn = new OleDbConnection("Provider=SQLNCLI11; server=localhost\\SQLEXPRESS; Database=<my db>; user id=<my uid>; password=<my pwd>");
cn.Open();
OleDbTransaction tn = cn.BeginTransaction();
OleDbCommand cmd = new OleDbCommand("INSERT INTO LAYOUTSv2 (LAYOUTS_name_t, LAYOUTS_enabled_b, LAYOUTS_data_m) VALUES ('name', '-1', 'data')", cn, tn);
cmd.ExecuteNonQuery();
cmd.CommandText = "SELECT SCOPE_IDENTITY()";
int newkey = Decimal.ToInt32((decimal)cmd.ExecuteScalar());
Console.WriteLine("Created index " + newkey);
Thread.Sleep(15000);
tn.Commit();
tn = cn.BeginTransaction();
cmd.CommandText = "UDPATE LAYOUTSv2 SET LAYOUTS_enabled_b='-3' WHERE LAYOUTS_key='" + newkey + "'";
cmd.Transaction = tn;
cmd.ExecuteNonQuery();
Console.WriteLine("updated row");
Thread.Sleep(15000);
tn.Rollback();
cn.Close();
Run Code Online (Sandbox Code Playgroud)

我运行此代码,然后从管理工作室运行SELECT * FROM LAYOUTSv2. 在客户端线程暂停(即在提交/回滚之前)的两种情况下,SELECT 查询会挂起,直到发生提交/回滚。

该表具有分配为主键的字段 LAYOUTS_key。在属性窗口中,它显示它是唯一的和集群的,同时允许页锁和行锁。该表的锁定升级设置为禁用...我已经尝试了其他可用的 Table 和 AUTO 设置,但没有进行任何更改。我已经尝试过SELECT ... WITH (NOLOCK)并且会立即返回结果,但是正如这里和其他地方所谨慎的那样,这不是我应该做的。我试过ROWLOCKINSERTUPDATE语句上都加上提示,但没有任何改变。

我正在寻找的行为是这样的:在提交 an 之前INSERT,来自其他线程的查询读取除正在INSERT编辑的行之外的所有行。在提交UPDATE来自其他线程的查询之前,读取正在UPDATE编辑的行的起始版本。有什么办法可以做到这一点吗?如果我需要提供其他信息来阐明我的用例,请告诉我。谢谢。

Mar*_*ith 11

有可能它没有锁定“整个表”。

它正在锁定表中的一行,但您SELECT * FROM LAYOUTSv2尝试读取整个表,因此必然会被该锁阻塞。

对于插入案例,您只需指定READPAST跳过锁定行的提示 - 但是这不会给出您想要的UPDATE案例结果(它将再次跳过该行而不读取该行的起始版本)。

如果您将数据库配置为读取提交的快照隔离,这将在两种情况下产生您想要的效果(以更多地使用 为代价tempdb


小智 9

插入和更新语句应该创建行级锁。但是,当任何事务中的锁数为 5,000 或更多时,就会发生锁升级并创建表级锁。请参阅下文。

https://technet.microsoft.com/en-us/library/ms184286(v=sql.105).aspx