只读行会触发数据库死锁吗?
Posted
技术标签:
【中文标题】只读行会触发数据库死锁吗?【英文标题】:Can read-only rows trigger database deadlocks? 【发布时间】:2014-09-04 22:44:49 【问题描述】:跟进https://***.com/a/16553083/14731...
我了解维护表的组合锁定顺序以减少死锁频率很重要,并且这会影响 UPDATE
和 SELECT
语句 [1]。但是,对于只读行是否同样适用?
如果一行在初始化时被填充一次并且没有人再次修改它,那么我们访问它的顺序真的很重要吗?
给定两个事务:T1、T2 和两个只读行 R1、R2
T1 读取 R1,然后读取 R2 T2 读取 R2,然后读取 R1
即使我使用 SERIALIZABLE 事务隔离,事务是否会死锁?
[1] 如果事务隔离为REPEATABLE_READ
, T1 SELECT
s R1, R2 而T2 UPDATE
s R2, R1 可能会发生死锁。
澄清:这个问题不是 RDBMS 特有的。我的印象是没有实现可以在只读行上死锁。如果您有反例(针对具体供应商),请发布一个答案来证明这一点,我会接受。或者,发布您可以证明不会死锁的所有具体实现的列表(并且最完整的列表将被接受)。
【问题讨论】:
您使用的是什么品牌的 RDBMS?请标记您的问题。每个供应商可能都有影响答案的实施细节。 @BillKarwin,我的印象是答案将跨越所有实现。如果您有一个声明的具体示例,该声明在一个供应商上而在另一个供应商上没有死锁,请发布一个答案来证明这一点,我会接受它。 嗯,例如 mysql 的 InnoDB 引擎不会在读取时锁定,因此除了多个写入者之间不会发生死锁。任何使用 MVCC 架构的实现都可能是这种情况。 @BillKarwin,澄清一下:问题是问“您是否知道发生死锁的任何实现?如果是,请提供一个具体示例。” 我不知道,但我不是锁定每个 RDBMS 实现的专家。 【参考方案1】:对于所有可能的 RDBMS,这个问题是不可能回答的,因为锁定策略是一个实现细节。也就是说,有用的 RDBMS 将具有一些共同特征:
对于没有应用提示的SELECT
语句(FOR UPDATE
、WITH (UPDLOCK)
、...),任何合理的 RDBMS 都不会使用写锁。它可能需要读锁。事实上,除了 Hekaton 表之外,至少 SQL Server 对 SERIALIZABLE
这样做了。
读锁从不冲突。 如果只执行读取,则不会出现死锁。
然而,只读行即使从未被写入也会导致死锁。在 SQL Server 中,
UPDATE T SET SomeCol = 1 WHERE ID = 10 AND SomeCol = 0
将在 ID 为 10 的行上使用 U 锁。如果 SomeCol 不为 0,则锁将立即释放并且不会写入任何内容。但 U 型锁是一种可能会发生冲突并导致死锁的锁类型。如果 ID 为 10 的行不存在,就不会出现死锁。
【讨论】:
示例UPDATE T SET SomeCol = 1 WHERE ID = 10 AND SomeCol = 0
中的只读行在哪里?我假设与 WHERE
子句匹配的行不是只读的,因为您正在更新它。
@Gili 因为 WHERE 不匹配它永远不会被写入。如果有ID = 11
的行,您也不会说该行正在更新。在这方面,ID = 11
的行和ID = 10 AND FALSE
的行是等价的。未更新。
所以你说不匹配的行会暂时被写锁定,但是一旦数据库注意到它们不匹配,锁就会被删除。正确的?我认为这种行为不会触发死锁,因为典型的锁超时以秒为单位(50 seconds for MySQL 和1 second for Postgres)而锁通常在 5 毫秒内被获取和释放。
正确。您不能使用基于挂钟的时间来说明什么是可能的,什么是不可能的。所有现代操作系统都可以随时引入任意延迟。
很公平。感谢您的澄清。以上是关于只读行会触发数据库死锁吗?的主要内容,如果未能解决你的问题,请参考以下文章