数据库中的锁
- ACID(原子性,一致性,隔离性和持久性)
- ACID是指数据库管理系统(DBMS)在写入或更新资料的过程中,为保证事务(transaction)是正确可靠的,所必须具备的四个特性:原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性(durability)。
- 原子性(Atomicity)
- 一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。
- 一致性(Consistency)
- 在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。
- 隔离性(Isolation)
- 数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括未提交读(Read uncommitted)、提交读(read committed)、可重复读(repeatable read)和串行化(Serializable)。
- 持久性(Durability)
- 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
- 原子性(Atomicity)
- ACID是指数据库管理系统(DBMS)在写入或更新资料的过程中,为保证事务(transaction)是正确可靠的,所必须具备的四个特性:原子性(atomicity,或称不可分割性)、一致性(consistency)、隔离性(isolation,又称独立性)、持久性(durability)。
- 事务 (Transaction:)
- 事务是进程中最小的堆栈,不能分成更小的部分。此外,某些事务处理组可以按顺序执行,但正如我们在原子性原则中所解释的那样,即使其中一个事务失败,所有事务块也将失败。
- 锁定 (Lock)
- 锁定是一种确保数据一致性的机制。SQL Server在事务启动时锁定对象。事务完成后,SQL Server将释放锁定的对象。可以根据SQL Server进程类型和隔离级别更改此锁定模式。这些锁定模式是:
- DataBase ->Table -> Page -> Row
- 共享(S)锁 (Shared (S) Locks)
- 当需要读取对象时,会发生此锁定类型。这种锁定类型不会造成太大问题。
- 独占(X)锁定 (Exclusive (X) Locks)
- 发生此锁定类型时,会发生以防止其他事务修改或访问锁定对象。
- 更新(U)锁 (Update (U) Locks)
- 此锁类型与独占锁类似,但它有一些差异。我们可以将更新操作划分为不同的阶段:读取阶段和写入阶段。在读取阶段,SQL Server不希望其他事务有权访问此对象以进行更改,因此,SQL Server使用更新锁。
- 意图锁定 (Intent Locks)#
- 当SQL Server想要在锁定层次结构中较低的某些资源上获取共享(S)锁定或独占(X)锁定时,会发生意图锁定。实际上,当SQL Server获取页面或行上的锁时,表中需要设置意图锁。
- 锁定是一种确保数据一致性的机制。SQL Server在事务启动时锁定对象。事务完成后,SQL Server将释放锁定的对象。可以根据SQL Server进程类型和隔离级别更改此锁定模式。这些锁定模式是:
- 根据官方文档的描述存在以下任一条件,则会触发锁定升级:
- 单个Transact-SQL语句在单个非分区表或索引上获取至少5,000个锁。
- 单个Transact-SQL语句在分区表的单个分区上获取至少5,000个锁,并且ALTER TABLE SET LOCK_ESCALATION选项设置为AUTO。
- 数据库引擎实例中的锁数超过了内存或配置阈值。
- https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-2008-r2/ms184286(v=sql.105)
- 如何避免锁升级
- 防止锁升级的最简单,最安全的方法是保持事务的简短,并减少昂贵查询的锁占用空间,以便不超过锁升级阈值,有几种方法可以实现这一目标.
- 将大批量操作分解为几个较小的操作
- 删除大量数据的时候,可以一次只删除500个,执行多次,可以显着减少每个事务累积的锁定数量并防止锁定升级。
- 创建索引使查询尽可能高效来减少查询的锁定占用空间
- 如果没有索引会造成表扫描可能会增加锁定升级的可能性, 更可怕的是,它增加了死锁的可能性,并且通常会对并发性和性能产生负面影响。
- 根据查询条件创建合适的索引,最大化提升索引查找的效率,此优化的一个目标是使索引查找返回尽可能少的行,以最小化查询的的成本。
- 如果其他SPID当前持有不兼容的表锁,则不会发生锁升级
- 锁定升级始总是升级成表锁,而不会升级到页面锁定。如果另一个SPID持有与升级的表锁冲突的IX(intent exclusive)锁定,则它会获取更细粒度的级别(行,key或页面)锁定,定期进行额外的升级尝试。表级别的IX(intent exclusive)锁定不会锁定任何行或页面,但它仍然与升级的S(共享)或X(独占)TAB锁定不兼容。
- 防止锁升级的最简单,最安全的方法是保持事务的简短,并减少昂贵查询的锁占用空间,以便不超过锁升级阈值,有几种方法可以实现这一目标.
- SQL Server提供了许多动态管理视图来访问指标。要识别SQL Server锁,我们可以使用sys.dm_tran_locks视图。在此视图中,我们可以找到有关当前活动锁管理的大量信息。
- 参考文献:
- SQL Server Transaction Locking and Row Versioning Guide https://docs.microsoft.com/en-us/previous-versions/sql/sql-server-guides/jj856598(v=sql.110)
- SQL Server, Locks Object https://docs.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-locks-object?view=sql-server-2017
- How to resolve blocking problems that are caused by lock escalation in SQL Server https://support.microsoft.com/es-ve/help/323630/how-to-resolve-blocking-problems-that-are-caused-by-lock-escalation-in
- Main concept of SQL Server locking https://codingsight.com/main-concept-of-sql-server-locking/