这两个语句的关系数据库是否可能出现死锁?我正在尝试简化我的问题和示例 - 请假设这些选择,我认为通常只需要可共享的读锁定,现在需要独占的读锁:
Concurrent Connection 1:
SELECT {...}
FROM A
JOIN B ON {...}
Concurrent Connection 2:
SELECT {...}
FROM B
JOIN A ON {...}
那就是,连接的顺序是否重要? SQL中的单个语句是原子的吗?首先锁定A然后在第一个语句中B和B先锁定然后在第二个语句中锁定A?
我认为不是 - 我的直觉告诉我,无论多么复杂,这样的两个单一陈述都不会陷入僵局。我相信整个语句是分析的,并且需要锁定的资源是使用一些确定性的全局顺序(即按字母顺序)锁定的。但我需要的不仅仅是对此的直觉 - 我无法想出一种证明它的方法,而且我无法找到它。
我对MS SQL 2005很感兴趣,但我不认为这个问题是特定于实现的。
其次:由于它与MS SQL有关,我还想知道Common Table Expressions也有这种保证--CTE主要是语法上的好处(+递归),由引擎合并为传统的单个语句。
答案 0 :(得分:9)
SELECT不能与其他SELECT死锁,因为它们只获取共享锁。你说我们应该考虑这些SELECT现在'需要独占读锁',但我们不可能考虑因为1)没有exlusive read lock
和2)读取不获取独占锁。
但是你确实提出了一个更普遍的问题,简单的陈述是否会陷入僵局。答案是肯定的,响亮的是。锁是在执行时获取的,不是预先分析的,而是按某种顺序排序然后获取。引擎不可能预先知道所需的锁,因为它们依赖于磁盘上的实际数据,并且读取引擎需要的数据......锁定数据。
由于索引访问顺序不同,简单语句(SELECt与UPDATE或SELECT与DELETE)之间的死锁非常常见,非常容易调查,诊断和修复。但请注意,始终涉及写入操作,因为读取不能相互阻塞。对于此讨论,将UPDLOCK或XLOCK提示添加到SELECT应视为写入。您甚至不需要JOIN,二级索引可能会引入导致死锁的访问顺序问题,请参阅Read/Write Deadlock。
最后,撰写SELECT FROM A JOIN B
或撰写SELECT FROM B JOIN A
完全无关紧要。查询优化器可以根据需要重新排列访问顺序,查询的实际文本不会以任何方式强加执行顺序。
<强>更新强>
那么我们如何构建一个将军呢? 针对READ COMMITTED的策略 “多实体”数据库即 没陷入僵局?
我担心没有千篇一律的食谱。解决方案将视具体情况而定。最终,在数据库应用程序中,死锁是生活中的事实。我知道这可能听起来很荒谬,因为“我们登陆月球但我们无法编写正确的数据库应用程序”,但有很多因素在起作用,这几乎可以保证应用程序最终会遇到死锁。幸运的死锁是 最容易处理错误,简单再次读取状态,应用逻辑,重新写入新状态。现在有人说,有一些好的做法可以大大减少死锁的频率,直到它们几乎消失了:
Customers
- &gt; OrderHeaders
- &gt; OrderLines
“。请注意,必须在事务中遵守该订单。基本上,在架构中对所有表进行排名,并指定所有更新必须按排名顺序进行。这最终归结为编写代码的个人贡献者的代码规则,因为它必须确保它写入事务中的正确顺序更新。尝试用LockCustomerByXXX
方法解决这个问题我恐怕不行。悲观锁定不会扩展。如果您想获得任何体面的表现,Optimistic concurrency更新 即可。
答案 1 :(得分:0)
据我所知,你是对的:SQL引擎计算出它需要做什么(可能是在解析查询时),锁定所有必需的资源,执行查询,然后解锁它们。
答案 2 :(得分:0)
读取不会相互死锁。你也必须有一些写作。
您可以采取措施减少死锁数量。例如,仅在支持行锁定的平台上的聚簇索引的末尾插入并避免更新记录。啊哈,现在Facebook的UI更有意义。
有时比处理死锁更容易处理死锁。服务器将失败并报告回来,您可以重试。