为 SQL Server 设计一个锁来帮助缓解 INSERT 和 SELECT 之间的冲突

Posted

技术标签:

【中文标题】为 SQL Server 设计一个锁来帮助缓解 INSERT 和 SELECT 之间的冲突【英文标题】:Design a Lock for SQL Server to help relax the conflict between INSERT and SELECT 【发布时间】:2012-03-30 17:58:11 【问题描述】:

SQL Server 是 SQL Azure,基本是 SQL Server 2008 的正常进程。

我有一个表,名为TASK,不断有新数据进入(新任务),并被删除(任务完成)

对于新数据,我使用INSERT INTO .. SELECT ...,大部分时间需要很长时间,比如说十几分钟。

对于旧数据,我先用SELECT (WITH NOLOCK)获取任务,UPDATE让其他线程知道这个任务已经开始处理,然后DELETE完成。

死锁有时发生在SELECT,大部分时间发生在UPDATEDELETE

这不是时间关键的任务,所以我可以在所有 INSERT 完成后开始处理新数据。是否有任何类型的 LOCK 要求 SELECT 在 INSERT 完成之前不要选择它?或任何其他避免冲突的建议。如果需要,我可以重新设计表格。

【问题讨论】:

SELECT...nolock... 根据定义不能建立锁,因此不应该参与死锁。您的意思是 INSERT...SELECT... 是死锁的一部分吗? 我猜发生的事情是:UPDATE 或 DELETE 踢了仍在 INSERT 过程中的行。所以,如果不首先选择它,那么就不会再出现死锁了。 所有这些都应该在读一致性模式下完成。所以任何在 INSERT 中间但尚未提交的东西都不能被另一个事务删除。 “几十分钟”意味着巨大的表格、笨拙的进程和/或糟糕或没有索引。很多事情可能在这里发生。我们需要了解更多,才能给出比一般意见更好的意见。 【参考方案1】:

后来的sqlserver2005,解决锁很容易。 为冲突 1.您可以使用服务代理。 2.使用隔离级别。

dbcc useroptions,在最后一行,可以看到deflaut隔离级别是read_committed,这是会话级别。 我们可以将级别更改为read_committed_snapshot冲突,在sqlserver中,不是像oracle那样真正的行锁。但是我们可以使用这种方法实现。

ALTER DATABASE DBName 设置 READ_COMMITTED_SNAPSHOT 开启;

开启此功能,必须在单机模式下。

你可以测试它。 对于会话 A,会话 B。

A:update table1 set name = 'new' with(Xlock) where id = 1 B:您仍然更新其他行并从表中选择所有数据。

我的英语不是很好,但是我知道锁。

在sqlserver中,对于函数,有三个锁。 1.乐观锁,使用时间戳(行版本)控制。 2.悲观锁定,使用日期时强制锁定。使用Ulock,Xlock等。 3.虚拟锁,使用proc getapplock()。

如果您需要系统架构中的lock schame,请发邮件至:mjjjj2001@163.com

【讨论】:

【参考方案2】:

如果这是一个处理队列,请考虑使用服务代理。

有许多因素会影响性能和锁定。我推测数据正在单独的会话中更新和删除。插入会话和删除会话正在使用哪个事务隔离级别。

删除会话运行时插入会话和所有事务是否已提交并关闭?是否有多个删除会话同时运行?对用于识别 SELECT/UPDATE/DELETE 语句的任务的列进行索引非常重要,尤其是当您移动到更高的隔离级别(如 REPEATABLE READ 或 SERIALIZED)时。

如果合适的话,所有这些问题都可以通过迁移到 Service Broker 来解决。

【讨论】:

SELECT/UPDATE/DELETE 是同时进行的。只有 INSERT 是单例的。有没有办法锁定行并标记它不能被选择,然后在插入后解锁(取消标记)它。那里有索引,我知道并发是问题的根本原因,但为了性能,我必须使用并发进程。我想我的问题可以简单地问:有没有办法在插入完成之前使该行不可选择? 默认为不可选择。但是通过使用 with(nolock) 你会覆盖它。如果要锁定行,为什么要使用 nolock?

以上是关于为 SQL Server 设计一个锁来帮助缓解 INSERT 和 SELECT 之间的冲突的主要内容,如果未能解决你的问题,请参考以下文章

mysql 发生死锁问题请求帮助

在 SQL Server 中为默认值或绑定生成脚本

好用的SQL Server数据库设计更新工具

SQL Server 中WITH (NOLOCK)

数据库在进行CHECKDB时出现 SQL Server 检测到基于一致性的逻辑 I/O 错误

SQL Server 2017 AlwaysOn AG 自动初始化