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

相关文章

MySQL的JDBC编程详解

《MySQL的JDBC编程详解》:本文主要介绍MySQL的JDBC编程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录前言一、前置知识1. 引入依赖2. 认识 url二、JDBC 操作流程1. JDBC 的写操作2. JDBC 的读操作总结前言本文介绍了mysq

java.sql.SQLTransientConnectionException连接超时异常原因及解决方案

《java.sql.SQLTransientConnectionException连接超时异常原因及解决方案》:本文主要介绍java.sql.SQLTransientConnectionExcep... 目录一、引言二、异常信息分析三、可能的原因3.1 连接池配置不合理3.2 数据库负载过高3.3 连接泄漏

Linux下MySQL数据库定时备份脚本与Crontab配置教学

《Linux下MySQL数据库定时备份脚本与Crontab配置教学》在生产环境中,数据库是核心资产之一,定期备份数据库可以有效防止意外数据丢失,本文将分享一份MySQL定时备份脚本,并讲解如何通过cr... 目录备份脚本详解脚本功能说明授权与可执行权限使用 Crontab 定时执行编辑 Crontab添加定

Debian 13升级后网络转发等功能异常怎么办? 并非错误而是管理机制变更

《Debian13升级后网络转发等功能异常怎么办?并非错误而是管理机制变更》很多朋友反馈,更新到Debian13后网络转发等功能异常,这并非BUG而是Debian13Trixie调整... 日前 Debian 13 Trixie 发布后已经有众多网友升级到新版本,只不过升级后发现某些功能存在异常,例如网络转

MySQL中On duplicate key update的实现示例

《MySQL中Onduplicatekeyupdate的实现示例》ONDUPLICATEKEYUPDATE是一种MySQL的语法,它在插入新数据时,如果遇到唯一键冲突,则会执行更新操作,而不是抛... 目录1/ ON DUPLICATE KEY UPDATE的简介2/ ON DUPLICATE KEY UP

MySQL分库分表的实践示例

《MySQL分库分表的实践示例》MySQL分库分表适用于数据量大或并发压力高的场景,核心技术包括水平/垂直分片和分库,需应对分布式事务、跨库查询等挑战,通过中间件和解决方案实现,最佳实践为合理策略、备... 目录一、分库分表的触发条件1.1 数据量阈值1.2 并发压力二、分库分表的核心技术模块2.1 水平分

Python与MySQL实现数据库实时同步的详细步骤

《Python与MySQL实现数据库实时同步的详细步骤》在日常开发中,数据同步是一项常见的需求,本篇文章将使用Python和MySQL来实现数据库实时同步,我们将围绕数据变更捕获、数据处理和数据写入这... 目录前言摘要概述:数据同步方案1. 基本思路2. mysql Binlog 简介实现步骤与代码示例1

Ubuntu如何升级Python版本

《Ubuntu如何升级Python版本》Ubuntu22.04Docker中,安装Python3.11后,使用update-alternatives设置为默认版本,最后用python3-V验证... 目China编程录问题描述前提环境解决方法总结问题描述Ubuntu22.04系统自带python3.10,想升级

解决升级JDK报错:module java.base does not“opens java.lang.reflect“to unnamed module问题

《解决升级JDK报错:modulejava.basedoesnot“opensjava.lang.reflect“tounnamedmodule问题》SpringBoot启动错误源于Jav... 目录问题描述原因分析解决方案总结问题描述启动sprintboot时报以下错误原因分析编程异js常是由Ja

Python 基于http.server模块实现简单http服务的代码举例

《Python基于http.server模块实现简单http服务的代码举例》Pythonhttp.server模块通过继承BaseHTTPRequestHandler处理HTTP请求,使用Threa... 目录测试环境代码实现相关介绍模块简介类及相关函数简介参考链接测试环境win11专业版python