什么决定了多表查询的锁定顺序?
Posted
技术标签:
【中文标题】什么决定了多表查询的锁定顺序?【英文标题】:What determines the locking order for a multi-table query? 【发布时间】:2013-05-14 20:09:31 【问题描述】:SQL 标准是否指定了多表查询的锁定顺序?
例如,给定:
SELECT department.id FROM permissions, terminals, departments WHERE department.id = ? AND terminal.id = ? AND permissions.parent = department.id AND permissions.child = terminals.id;
-
SQL 标准是否保证锁定顺序,还是由(特定于实现的)执行计划确定?
有没有办法保证锁定顺序?
如果没有办法保证锁定顺序,我们应该如何防止死锁?
更新:请不要在未解释原因的情况下投票关闭此问题。就我而言,这是一个编程问题,这使它成为 *** 的热门话题。如果您认为该问题需要进一步完善,请解释,我将非常乐意为您解答。
【问题讨论】:
SELECT 查询不会生成导致死锁的锁。您能否重新表述您的问题,使其与实际情况相关? @GordonLinoff,READ_COMMITTED 中的 SELECT 查询确实会生成锁(但在语句期间)。对于其他隔离级别(例如 REPEATABLE_READ 或 SERIALIZABLE),它们会保留锁定直到事务结束。警告:一些数据库使用不使用任何锁的 MVCC,但这些超出了这个问题的范围。 锁是一个实现细节。隔离级别仅指定可以/不发生的现象。在 SQL Server 中,读取提交时的选择查询大多采用S
锁,一旦读取数据(在语句结束之前)就会释放这些锁。有时这些锁可以保留到语句结束,但是example 和其他时候它根本不需要行级S
锁。除非您指定特定的 RDBMS,否则第 1 点和第 2 点和第 3 点是无法回答的。
READ_COMMITTED 隔离级别的查询使用共享读锁。我希望数据库可以在单个原子操作中获取所有必需的锁。提交可能会或可能不会阻止读取 - 我希望大多数企业数据库足够聪明以避免这种情况
@MartinSmith,请发布答案,以便我们更详细地阐述您的观点。
【参考方案1】:
根据https://***.com/a/112256/14731锁定顺序由特定于实现的执行顺序决定。答案进一步说没有确定的方法来防止死锁。在命令式编程中,我们可以通过以相同顺序获取锁来防止死锁,而在声明式系统中,我们似乎必须通过在检测到死锁时重试操作来解决这些问题。
此外,我认为,由于数据库执行计划在其生命周期内发生变化,因此在技术上不可能防止死锁。
【讨论】:
请注意,您提到的答案中的“当您以相同的顺序访问表时”这句话是指更新语句的顺序。连接查询中表的顺序不会对死锁的概率产生太大影响,因为查询只创建 S 个锁。运行相同查询的两个事务不会相互锁定。 @nakosspy,查询同一组表但顺序不同的两个事务可能会导致死锁(至少对于幼稚的数据库实现而言)。换句话说,我同意你的观点,运行相同的查询不会导致死锁,但关键是即使没有UPDATE
的SELECT
也会导致死锁。
简单的数据库实现是什么意思?为查询获取排他锁的数据库?我不知道有任何数据库可以做到这一点。但是,如果您必须处理这样一个“幼稚”的数据库,那么主要问题将是数据完整性和性能,而不是死锁。
@nakosspy,我的错。你说的对。我没有意识到“S 锁”意味着读锁。是的,如果你只有SELECT
,那么锁定顺序就无关紧要(但实际上,每个人都需要INSERT
和UPDATE
)。在您引入使用写锁的单个语句的那一刻,它就有可能触发死锁(意思是,SELECT
可能正在等待UPDATE
持有的锁,反之亦然)。【参考方案2】:
我可以为您提供 DB2 的答案,但我认为这对于其他数据库也应该类似。首先,一切都取决于表的 locksize 参数。此参数定义要锁定的内容。你可以有 locksize = table、page 或 row。因此,根据每个表的锁定大小,数据库将锁定用于为游标获取数据的对象(表、页或行)。因此,创建锁的顺序将由访问路径指定,这取决于优化器。
【讨论】:
所以你是说这取决于特定于实现的执行计划?如果是这样,那么问题 3 呢? 首先这些锁都是S锁。这意味着不允许其他事务更新游标使用的页面(或行)。如果您打开游标并且您的隔离级别是读取稳定性,则不允许其他任何人修改您的游标读取的数据。您的交易被允许修改这些数据。如果你想尽量减少死锁,那么优先选择行锁而不是页或表,并将隔离级别设置为游标稳定性。以上是关于什么决定了多表查询的锁定顺序?的主要内容,如果未能解决你的问题,请参考以下文章