SQL死锁问题

Jas*_*ban 4 sql sql-server-2005 database-deadlocks

在这两个语句的关系数据库中是否可能出现死锁?我正在尝试简化我的问题和示例 - 请假设这些选择,我认为通常只需要可共享的读锁定,现在需要独占的读锁:

Concurrent Connection 1:
SELECT {...}
FROM A 
JOIN B ON {...}

Concurrent Connection 2:
SELECT {...}
FROM B 
JOIN A ON {...}
Run Code Online (Sandbox Code Playgroud)

也就是说,连接的顺序是否重要?SQL中的单个语句是原子的吗?首先锁定A然后在第一个语句中B和B先锁定然后在第二个语句中锁定A?

我想不是 - 我的直觉告诉我,这样的两个单一陈述不会陷入僵局,无论多么复杂.我相信一个声明作为一个整体被分析,并且需要锁定的资源使用一些确定性的全局顺序(即按字母顺序)被锁定.但我需要的不仅仅是一种直觉 - 我无法想出一种证明它的方法,而且我无法找到它.

我对MS SQL 2005很感兴趣,但我不认为这个问题是特定于实现的.

其次:由于它与MS SQL有关,我还想知道Common Table Expressions也有这种保证--CTE主要是语法上的好处(+递归),并由引擎整合到传统的单个语句中.

Rem*_*anu 9

SELECT不能与其他SELECT死锁,因为它们只获取共享锁.你说我们应该考虑这些SELECT现在'需要独占读锁',但是这不可能让我们考虑因为1)没有这样的东西exlusive read lock和2)读取不获取独占锁.

但是你确实提出了一个更普遍的问题,简单的陈述是否会陷入僵局.答案是肯定的,响亮的.锁在执行时获取,不是预先分析,然后按某种顺序进行分类.引擎不可能预先知道所需的锁,因为它们依赖于磁盘上的实际数据,并且读取引擎需要的数据......锁定数据.

由于索引访问顺序不同,简单语句(SELECt与UPDATE或SELECT与DELETE)之间的死锁非常常见,非常容易调查,诊断和修复.但请注意,总是涉及写入操作,因为读取不能相互阻塞.对于此讨论,将UPDLOCK或XLOCK提示添加到SELECT应视为写入.您甚至不需要JOIN,二级索引可能会引入导致死锁的访问顺序问题,请参阅读/写死锁.

最后,写作SELECT FROM A JOIN B或写作SELECT FROM B JOIN A完全无关紧要.查询优化器可以根据需要重新排列访问顺序,查询的实际文本不会以任何方式强加执行顺序.

更新

那么我们如何构建一个没有死锁的READ COMMITTED"多实体"数据库的一般策略呢?

我担心没有千篇一律的食谱.解决方案将视具体情况而定.最终,在数据库应用程序中,死锁是生活中的事实.我知道这可能听起来很荒谬,因为"我们登陆月球但我们无法编写正确的数据库应用程序",但有很多因素在起作用,这几乎可以保证应用程序最终会遇到死锁.幸运的是死锁最简单的处理错误,再简单的读状态,应用逻辑,重新写新的状态.现在有人说,有一些好的做法可以大大减少死锁的频率,直到它们几乎消失了:

  • 尝试为Writes提供一致的访问模式.有明确定义的规则说明"交易应始终按此顺序排列表:Customers- > OrderHeaders- > OrderLines." 请注意,必须在交易中遵守订单.基本上,对模式中的所有表进行排名,并指定所有更新必须按排名顺序进行.这最终归结为编写代码的个体贡献者的代码规则,因为它必须确保它的写入是事务中正确的顺序更新.
  • 减少写入的持续时间.通常的智慧是:在事务开始时执行所有读取(读取现有状态),然后处理逻辑并计算新值,然后在事务结束时写入所有更新.避免使用类似'read-> write-> logic-> read-> write'的模式,而不是'read-> read-> logic-> write-> write'.当然,真正的工艺在于如何在明显必须的情况下处理实际的,真实的,个别的案件必须在交易中做写.这里必须特别说明一种特定类型的事务:由队列驱动的事务,它通过非常定义通过从队列中出列(=写入)来启动它们的活动.这些应用程序总是非常难以编写并且容易出错(特别是死锁),幸运的是有很多方法可以执行,请参阅将表用作队列.
  • 减少读取量.表扫描是导致死锁最常见原因.正确的索引不仅可以消除死锁,还可以提高过程中的性能.
  • 快照隔离.这是你在避免死锁方面最接近免费午餐的事情.我故意把它放在最后,因为它可能掩盖其他问题(如不正确的索引)而不是修复它们.

尝试用一种LockCustomerByXXX方法来解决这个问题我恐怕不行.悲观锁定不会扩展.如果您希望获得任何体面的性能,那么乐观的并发更新是可行方法.