代码之家  ›  专栏  ›  技术社区  ›  Jason Kleban

SQL死锁问题

  •  4
  • Jason Kleban  · 技术社区  · 15 年前

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

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

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

    我不这么认为-我的直觉告诉我,像这样的两个单独的语句不能死锁,无论多么复杂。我认为语句是作为一个整体进行分析的,需要锁定的资源是使用某种确定的全局顺序(即按字母顺序)锁定的。但我需要的不仅仅是直觉——我想不出一个方法来证明这一点,而且我也找不到文件证明。

    我对mssql2005感兴趣,但我不认为这个问题是特定于实现的。

    第二点:由于它与MS SQL有关,我还想知道常见的表表达式也有这样的保证——CTE主要是一种语法优势(+递归),由引擎合并成传统的单个语句。

    3 回复  |  直到 15 年前
        1
  •  9
  •   Remus Rusanu    15 年前

    SELECT不能与其他SELECT死锁,因为它们只获取共享锁。你说我们应该考虑这些选择现在'需要独占读锁',但这是我们不可能考虑的,因为1)没有一个 exlusive read lock

    但你确实提出了一个更一般的问题,简单的语句是否会死锁。答案是明确的,响亮的 . 锁是在执行时获取的,而不是预先分析和排序,然后按某种顺序获取。引擎不可能预先知道所需的锁,因为它们取决于磁盘上的实际数据,而要读取引擎需要的数据。。。锁定数据。

    由于索引访问顺序不同,简单语句(SELECt vs.UPDATE或SELECt vs.DELETE)之间的死锁非常常见,并且非常容易调查、诊断和修复。但请注意 总是 所涉及的一种写操作,因为读操作不能相互阻塞。对于本讨论,向SELECT添加UPDLOCK或XLOCK提示应视为写入。您甚至不需要连接,辅助索引很可能会引入导致死锁的访问顺序问题,请参阅 Read/Write Deadlock .

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

    更新

    读承诺策略 “多实体”数据库

    这个 最容易处理错误,简单的重新读取状态,应用逻辑,重新写入新状态。话虽如此,但有一些好的做法可以大大减少死锁的发生频率,直至死锁几乎消失殆尽:

    • 写入 . 有明确规定的规则,如“交易应始终按以下顺序进行: Customers -&燃气轮机; OrderHeaders -&燃气轮机; OrderLines 注意,命令必须在 交易 全部的 并指定所有更新必须按排序顺序进行。这最终归结为单个贡献者编写代码的代码规则,因为它必须确保在事务中以正确的顺序进行更新。
    • 减少 期间 写的次数。通常的做法是这样的:在事务开始时进行所有读取(读取现有状态),然后处理逻辑并计算新值,然后在事务结束时写入所有更新。避免像“读取”这样的模式;写入->逻辑->读取->写',而不是读->读取->逻辑->写入->写'。当然,真正的技巧在于如何处理实际的、真实的、个别的案件 必须 Using tables as Queues .
    • 减少读取量。表格扫描是 这个 死锁最常见的原因。正确的索引不仅可以消除死锁,还可以提高过程中的性能。
    • Snapshot isolation 面具

    LockCustomerByXXX Optimistic concurrency 更新是 这个 如果你想有任何体面的表现,那就太好了。

        2
  •  0
  •   zebediah49    15 年前

        3
  •  0
  •   Marcus Adams    15 年前

    读取不会使彼此死锁。你一定也在写东西。

    您可以采取措施减少死锁的数量。例如,在支持行锁定并避免更新记录的平台上,只在聚集索引的末尾插入。啊哈,现在Facebook的UI更有意义了。

    有时处理死锁比避免它们容易。服务器将失败并报告,您可以重试。

    推荐文章