SQL SERVER 锁升级的 investigation 与 别吃黄连

2024-03-05 23:20

本文主要是介绍SQL SERVER 锁升级的 investigation 与 别吃黄连,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前些日子在分析SQL SERVER 死锁的过程中,检查有一些莫名其妙的死锁,两个根本不搭噶的事务,锁在了一起,WHY,其实SQL SERVER 在数据库界,算是一朵奇葩,独有的锁升级的技术,我想你应该不曾听到 MYSQL ,ORACLE , PG  ,MONGODB 这些数据库提及到的锁升级的问题。

而牵扯到锁升级到额问题,就需要提及,到底为什么锁升级,锁从哪里升级到哪里的问题。所以就有了这篇文字,关于锁升级的东西。

首先我们在谈论锁的时候,的先站在一个讨论的起跑线,就是锁是发生在内存级别的,并且锁的开始和结束都是伴随着“事务”的开始和结束。在达成如上的共识后我们就开始下面的一些讨论和研究。

当事务管理器接收到提交请求时,它向事务中涉及的所有资源管理器发送一个prepare命令。然后,每个资源管理器执行使事务持久所需的所有操作,并将保存事务日志映像的所有缓冲区刷新到磁盘。当每个资源管理器完成准备阶段时,它将准备的成功或失败返回给事务管理器。

如果事务管理器从所有资源管理器接收到成功的准备,它将向每个资源管理器发送提交命令。然后,资源管理器可以完成提交。如果所有资源管理器都报告提交成功,那么事务管理器将向应用程序发送成功通知。如果任何资源管理器报告准备失败,事务管理器将向每个资源管理器发送回滚命令,并指示向应用程序提交失败。

SQL SERVER 在什么时候会选择什么样的锁的因素可能有哪些 

下面是部分SQL SERVER 中可以进行锁的资源样本

RID没有建立聚簇索引(HEAP TABLE)中标识行 ROW ID
KEY索引中的行锁,用于在可序列化事务中保护键范围
PAGE8KB的page 页,作为一个锁定的单位
EXTENT连续的8 个页面,作为锁定的单位
HoBT堆或b树。保护表中没有聚集索引的b树(索引)或堆数据页的锁。
TABLE

问题:为什么要这么多锁的类型,MYSQL innodb 不仅仅有 row lock吗?

作为一个商业数据库,在设计之初SQL SERVER 考虑了下面一个图(假设),使用低级锁(如行锁)可以降低两个事务同时请求同一数据块上的锁的概率,从而提高并发性,但使用低级锁还会增加锁的数量和管理锁所需的资源反之使用表或页锁可以降低开销,但代价是降低并发性。

SQL Server数据库引擎使用动态锁定策略来确定最经济有效的锁。数据库引擎会根据模式和查询的特性自动确定在执行查询时哪些锁是最合适的。例如,为了减少锁定的开销,优化器可以在执行索引扫描时选择索引中的页级锁定。这样做的好处也是显而易见,如果我有多行在一个PAGE中,并且都需要更改,系统会根据需要索引的资源来锁定这个PAGE,而不是一个页面里面的每个行,因为要考虑每个锁的管理,申请,释放,都是需要相关CPU 资源,内存资源的,如果能在不影响并发度的情况下,锁的粒度有效控制是有助于系统的信息的访问和修改的。

并且SQL SERVER 也是可以在表的创建,或使用中进行锁释放可以自动进行升级的设置的,你可以打开表的锁升级,或禁止掉他。

说到这里不得不说说SQL SERVER 锁的历史 SQL SERVER 7.0 之前的时候,(应该不是我出生的时候,在很久很久很久久以前久以前),SQL SERVER 是不支持 ROW 锁的,而仅仅支持 PAGE LOCK,并且一个页面是 2KB ,在 SQL SERVER 7.0,他们将SQL SERVER 变为了 8KB 的PAGE ,并且开始支持了 ROW LOCK。那到底为什么 SQL SERVER 不能做成和MYSQL 一样,仅仅支持行锁就好的数据库,为什么单库的商业数据库还是有优势的(注意这是问句)

下面是一个行锁的结构

     锁是一个64或128字节的内存结构(分别用于32位或64位机器),每个持有或请求锁的进程都有另外32或64字节。如果您需要对每一行都使用锁,并且扫描一百万行,那么您需要超过64MB的RAM来保存该进程的锁。

一个语句在一个对象上持有的锁的数量超过了一个阈值。举例目前这个阈值是5000个锁,超过就会触发esclation,如果锁分布在同一语句中的多个对象上,则不会发生锁升级——例如,一个索引中的3000个锁和另一个索引中的3000个锁,另一方面锁资源占用的内存超过启用内存的40%,那么锁会将发生升级。

那锁升级到底是好不好,回答是  呵呵, 我想你明白我的意思。为什么

当触发锁升级时,如果存在冲突锁,则会先增加更多的X锁(我想你应该是懂这个过程的),并且不同进程持有的同一表或分区上有并发的X锁,则锁升级尝试将失败。每次事务在同一对象上获得另外更多个锁时,SQL Server都会继续尝试升级锁,成功后会将SQL Server索引或堆表上的所有行锁进行释放。

可以想想这个锁升级从上到下的描述中,触发他的伴随的是大事务,占用更多的内存,系统陷入了可能繁忙的状态,那此时进行锁升级,可能会成功,可能会失败,同时成功后,锁的级别将从ROW 变成 PAGE 或者更宽泛的锁,系统将由 SHARE 变为  ONLY You  use it . 其他的事务如果访问你的资源,你是不是就不在管他们死活。

这还不是最糟糕的,锁升级会导致更多的死锁的出现,并且是莫名其妙的,看似两个根本就无关的事务,也会锁在一起,我想这时候如果你的领导来询问你的时候为什么这么多莫名其妙的死锁时,你是不是已经可以,有理有据来和他 make  clear 一下了。

这篇关于SQL SERVER 锁升级的 investigation 与 别吃黄连的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/778143

相关文章

SQL server数据库如何下载和安装

《SQLserver数据库如何下载和安装》本文指导如何下载安装SQLServer2022评估版及SSMS工具,涵盖安装配置、连接字符串设置、C#连接数据库方法和安全注意事项,如混合验证、参数化查... 目录第一步:打开官网下载对应文件第二步:程序安装配置第三部:安装工具SQL Server Manageme

C#连接SQL server数据库命令的基本步骤

《C#连接SQLserver数据库命令的基本步骤》文章讲解了连接SQLServer数据库的步骤,包括引入命名空间、构建连接字符串、使用SqlConnection和SqlCommand执行SQL操作,... 目录建议配合使用:如何下载和安装SQL server数据库-CSDN博客1. 引入必要的命名空间2.

全面掌握 SQL 中的 DATEDIFF函数及用法最佳实践

《全面掌握SQL中的DATEDIFF函数及用法最佳实践》本文解析DATEDIFF在不同数据库中的差异,强调其边界计算原理,探讨应用场景及陷阱,推荐根据需求选择TIMESTAMPDIFF或inte... 目录1. 核心概念:DATEDIFF 究竟在计算什么?2. 主流数据库中的 DATEDIFF 实现2.1

MySQL 多列 IN 查询之语法、性能与实战技巧(最新整理)

《MySQL多列IN查询之语法、性能与实战技巧(最新整理)》本文详解MySQL多列IN查询,对比传统OR写法,强调其简洁高效,适合批量匹配复合键,通过联合索引、分批次优化提升性能,兼容多种数据库... 目录一、基础语法:多列 IN 的两种写法1. 直接值列表2. 子查询二、对比传统 OR 的写法三、性能分析

MySQL中的LENGTH()函数用法详解与实例分析

《MySQL中的LENGTH()函数用法详解与实例分析》MySQLLENGTH()函数用于计算字符串的字节长度,区别于CHAR_LENGTH()的字符长度,适用于多字节字符集(如UTF-8)的数据验证... 目录1. LENGTH()函数的基本语法2. LENGTH()函数的返回值2.1 示例1:计算字符串

浅谈mysql的not exists走不走索引

《浅谈mysql的notexists走不走索引》在MySQL中,​NOTEXISTS子句是否使用索引取决于子查询中关联字段是否建立了合适的索引,下面就来介绍一下mysql的notexists走不走索... 在mysql中,​NOT EXISTS子句是否使用索引取决于子查询中关联字段是否建立了合适的索引。以下

Python包管理工具pip的升级指南

《Python包管理工具pip的升级指南》本文全面探讨Python包管理工具pip的升级策略,从基础升级方法到高级技巧,涵盖不同操作系统环境下的最佳实践,我们将深入分析pip的工作原理,介绍多种升级方... 目录1. 背景介绍1.1 目的和范围1.2 预期读者1.3 文档结构概述1.4 术语表1.4.1 核

Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式

《Java通过驱动包(jar包)连接MySQL数据库的步骤总结及验证方式》本文详细介绍如何使用Java通过JDBC连接MySQL数据库,包括下载驱动、配置Eclipse环境、检测数据库连接等关键步骤,... 目录一、下载驱动包二、放jar包三、检测数据库连接JavaJava 如何使用 JDBC 连接 mys

SQL中如何添加数据(常见方法及示例)

《SQL中如何添加数据(常见方法及示例)》SQL全称为StructuredQueryLanguage,是一种用于管理关系数据库的标准编程语言,下面给大家介绍SQL中如何添加数据,感兴趣的朋友一起看看吧... 目录在mysql中,有多种方法可以添加数据。以下是一些常见的方法及其示例。1. 使用INSERT I

Qt使用QSqlDatabase连接MySQL实现增删改查功能

《Qt使用QSqlDatabase连接MySQL实现增删改查功能》这篇文章主要为大家详细介绍了Qt如何使用QSqlDatabase连接MySQL实现增删改查功能,文中的示例代码讲解详细,感兴趣的小伙伴... 目录一、创建数据表二、连接mysql数据库三、封装成一个完整的轻量级 ORM 风格类3.1 表结构