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主要是语法上的好处(+递归),并由引擎整合到传统的单个语句中.
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"多实体"数据库的一般策略呢?
我担心没有千篇一律的食谱.解决方案将视具体情况而定.最终,在数据库应用程序中,死锁是生活中的事实.我知道这可能听起来很荒谬,因为"我们登陆月球但我们无法编写正确的数据库应用程序",但有很多因素在起作用,这几乎可以保证应用程序最终会遇到死锁.幸运的是死锁的最简单的处理错误,再简单的读状态,应用逻辑,重新写新的状态.现在有人说,有一些好的做法可以大大减少死锁的频率,直到它们几乎消失了:
Customers- > OrderHeaders- > OrderLines." 请注意,必须在交易中遵守订单.基本上,对模式中的所有表进行排名,并指定所有更新必须按排名顺序进行.这最终归结为编写代码的个体贡献者的代码规则,因为它必须确保它的写入是事务中正确的顺序更新.尝试用一种LockCustomerByXXX方法来解决这个问题我恐怕不行.悲观锁定不会扩展.如果您希望获得任何体面的性能,那么乐观的并发更新是可行的方法.