【问题标题】:Deadlock happens on 1 single table with 2 users doing simple statement死锁发生在 1 个单表上,2 个用户执行简单语句
【发布时间】:2017-11-22 05:34:22
【问题描述】:

最终解决方案
我们实际上所做的是通过创建一个工作表和会话 ID 来绕过逐行插入,并拥有一个存储过程,可以一次从临时表删除和插入到主表。没有更多的死锁!
最终流程:

  • 从 TheTable_work 中删除(使用 sessionID,以防万一……)
  • INSERT INTO TheTable_work(使用 ADODB 逐行)
  • 我调用了一个存储过程:
    • 开始交易
    • 从 TheTable 中删除(带有一些 条件)
    • 从 TheTable_work 插入到 TheTable (1 声明)
    • 提交
  • 从 TheTable_work 中删除(清理)

我们确实认为这是因为索引锁定,但我正在等待 DBA 的确认(解释 here)。

隔离级别没有任何改变(我们尝试了所有可能性,甚至打开和关闭 READ_COMMITTED_SNAPSHOT)


当 2 个用户同时“写入”数据库时,我的应用程序会导致数据库死锁。它们不适用于相同的数据,因为它们具有不同的 id,但它们适用于同一张表。

用户 1 (id = 1),用户 2 (id = 2)

流程

User 1 does : 1 DELETE statement, followed by 3000 INSERT
User 2 does : 1 DELETE statement, followed by 3000 INSERT 

User 2 DELETE in the middle of user 1 INSERT (example : after 1500). Result in Deadlock. 

声明(示例,但它们有效)

DELETE FROM dbo.TheTable WHERE id = 1  /* Delete about 3000 lines */
INSERT INTO dbo.TheTable (id, field2, field3) VALUE (1 , 'value2','value3')

我使用 ADODB (Microsoft Access...),所以我执行了一个简单的查询,例如:

ConnectSQLServer.Execute "DELETE or INSERT statement"

错误信息

Run-time error '-2147457259 (80004005)':
Transaction (Process ID76) was deadlocked on lock resources with another process and has been chosen as the deadlock victim. Rerun the transaction. 

其他信息

  • 不涉及事务,只有简单的 INSERT 或 DELETE 查询, 一个一个
  • 没有涉及 RecordSet,也没有打开
  • 我们试图寻找死锁跟踪但没有显示图形,DBA 试图了解原因
  • 我想了解他们为什么会互相僵持,而不是“等”到另一个完成!我怎样才能做更好的操作? =)
  • Access : 它是一个带有 SQL-Server 后端的访问前端。没有链接表,vba 代码通过 ADODB 连接推送查询。

编辑:死锁图
左边有 1 个(共 3000 个)INSERT 语句,右边有一个 DELETE。

更新
我删除了 DELETE 语句中使用的列上的索引,我无法再重现死锁!不是一个干净的解决方案,而是暂时的。我们考虑在临时表中插入 3000 行,然后一次从临时表复制到 TheTable(在存储过程中删除和插入)。

谢谢,

塞伯

【问题讨论】:

  • “只有简单的INSERT或DELETE查询,一个一个”是什么意思?听起来您可能正在为此使用循环?但我也有点困惑。您的问题的 99.999% 显然是 sql server,但随后您提到了 Access。 Access是前端,所有的处理都在sql server吗?
  • 如果你想了解死锁,你需要一个deadlock trace。没有两种方法。如果您有很多经验,可以对死锁是什么以及如何最好地解决它进行有根据的猜测,但即便如此,这也是危险的,因为您仍然很容易猜错。没有任何痕迹,我有根据的猜测是您的表有多个索引,INSERTDELETE 将它们锁定在不同的、不兼容的顺序中,您通常通过战略性地增加锁定来解决这个问题。 但这是猜测
  • 您是否连接了 sql server 2012 并将访问用作链接表?
  • @SeanLange 和 M. Hassan : 抱歉访问混乱:它只是前端,没有链接表,我们使用 VBA 对 SQL-Server 进行 ADODB 查询。是的,有一个“循环”模式,因为用户输入内容并生成大约 3000 条 INSERT 语句,全部同时发送到数据库(一个接一个)。

标签: sql sql-server sql-server-2012 deadlock database-deadlocks


【解决方案1】:

DELETE 将在页面上持有更新锁:

更新(美国)

用于可以更新的资​​源。 防止常见的 当多个会话正在读取、锁定和锁定时发生的死锁 以后可能会更新资源。

INSERT 将在相同页面上持有意向/排他锁。

独家 (X)

用于数据修改操作,例如 INSERT、UPDATE 或 删除。 确保不能对同一个文件进行多次更新 资源。

意图

用于建立锁层次结构。意向锁的类型有: 意图共享 (IS)、意图独占 (IX) 和有意图共享 独家(六)。

如果您希望同时运行两个查询, 每个人都必须在给定的时间等待另一个人。

如果整个插入集不需要回滚,我建议您在单独的事务中运行每个插入。
或者,尝试移除并行化,或在不同时间执行这些操作。

简而言之:
1) 尝试确保每个 INSERT 都正确提交,然后再进行下一个。
2) 或者尽量避免同时做这两个操作

另一个猜测是为产生问题的会话调整事务隔离级别。检查以下文档。

参考:
Lock Modes
Transaction Isolation Level

【讨论】:

  • 感谢您的回答@Hybris95。我们不使用事务,我们只将每个查询一个接一个地发送到 SQL Server。我知道 2 个不同的用户同时发生 1 个 INSERT 和 1 个 DELETE 会导致死锁。这将很难阻止,因为查询字符串是由客户端发送的,而不是在服务器端发送的。我想知道他们是否可以完全独立(一个接一个地发生)。我尝试使用 BEGIN TRANS 和 COMMIT 这些 2 语句导致死锁。其他选择是在数据库中有一个“设置”,每个进程都会调用来询问他们是否可以写。
  • 似乎您的应用程序隐含地为整个插入/删除语句创建事务。对整个块使用事务将生成死锁,但也会确保回滚将回滚整个上下文,而不仅仅是最后插入的行。
  • 另外:您正在使用事务,只是没有明确表示。您的应用程序自己管理事务级别,请参阅我的答案的编辑考虑此选项
  • 感谢您的精确!我知道我正在使用事务,我应该自己管理它,而不是把它留给 ADODB!我回去工作! :)
  • 你看到我的更新了吗?通过删除索引,我解决了问题。你我不想让它成为一个永久的解决方案。我删除了 DELETE 语句中使用的列上的索引,我无法再重现死锁!不是一个干净的解决方案,而是暂时的。我们考虑在临时表中插入 3000 行,然后一次从临时表复制到 TheTable(在存储过程中删除和插入)。
猜你喜欢
  • 2020-11-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多