MySQL全局锁、表级锁、行锁、死锁、索引选择

文章目录

  • 全局锁
  • 表级锁
      • 表锁
      • 元数据锁 MDL
  • 如何安全的给小表添加字段
      • 1. 理解和监控长事务
      • 2. 使用NOWAIT和WAIT语法
        • 示例
      • 3. 选择合适的时间窗口
      • 4. 分阶段执行
      • 5. 使用在线DDL工具
  • 行锁
  • 死锁
  • 普通索引和唯一索引的选择
      • 索引基础
      • 业务场景分析
      • 性能考量
      • 实践建议
      • 索引及其选择机制
        • 索引选择错误的示例
          • 问题出现的条件
        • 优化器逻辑与决策因素
        • 索引的区分度和基数
        • 统计信息的角色
        • 解决方案和实践建议
      • 结论

本文为MySQL45讲 6-10的总结
根据加锁的范围可以分为全局锁、表级锁、行锁

全局锁

定义:对整个数据库实例加锁,让整个库处于只读状态

命令:Flush tables with read lock (FTWRL)

使用场景:做全库逻辑备份

不建议使用set global readonly=true的原因:

  1. 在有些系统中readonly会被用为其他逻辑
  2. 在异常处理机制上面有差异,FTWRL若客户端异常导致断开,MySQL会自动释放,但是如果用此方法,状态不会改变

存在的问题:当全局备份时,相关业务都会停摆, 但是不加锁的话,备份系统备份的得到的库不是一个逻辑时间点,这个视图是逻辑不一致的。如果开启事务,那么可重复读级别下是可以拿到一致性试图

官方自带的逻辑备份工具是mysqldump。当mysqldump使用参数–single-transaction的时候,导数据之前就会启动一个事务,来确保拿到一致性视图。而由于MVCC的支持,这个过程中数据是可以正常更新的。

表级锁

MySQL里面表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)。

表锁

语法: lock tables … read/write

特点:可以用unlock tables主动释放锁,也可以在客户端断开的时候自动释放。需要注意,lock tables语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象;是最常用的处理并发的方式

元数据锁 MDL

特点:不需要显示使用,在访问表时会自动加上

作用:保证读写的正确性

在MySQL 5.5版本中引入了MDL,当对一个表做增删改查操作的时候,加MDL读锁;当要对表做结构变更操作的时候,加MDL写锁。

  • 读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查。

  • 读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性。因此,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完才能开始执行。

  • 事务中的MDL锁,在语句执行开始时申请,等到整个事务提交后再释放。

如何安全的给小表添加字段

1. 理解和监控长事务

在进行任何DDL操作前,我们需要监控并处理可能存在的长事务。长事务会持有元数据锁(MDL),这会阻止DDL操作的执行。您可以通过以下SQL查询来检查长事务:

SELECT * FROM information_schema.innodb_trx WHERE TIME_TO_SEC(timediff(now(), trx_started)) > N;

这里的N是你定义的长事务的阈值(例如,60秒)。

2. 使用NOWAIT和WAIT语法

MySQL原生并不支持NOWAITWAIT语法。这是MariaDB一个特有的功能,继承自AliSQL。这些选项允许你控制DDL操作的等待行为:

  • NOWAIT:尝试立即获取锁,如果无法立即获得则操作失败。
  • WAIT N:等待指定的秒数以获取锁,如果指定时间内无法获取锁,操作也会失败。
示例

如果你正在使用MariaDB,可以这样使用:

ALTER TABLE tbl_name NOWAIT ADD COLUMN new_column INT;

或者:

ALTER TABLE tbl_name WAIT 10 ADD COLUMN new_column INT;

3. 选择合适的时间窗口

尽管NOWAITWAIT提供了更多的灵活性,选择执行DDL操作的时间仍然至关重要。选择低峰时段进行操作可以显著减少对业务的影响。

4. 分阶段执行

对于非常大或非常活跃的表,考虑分阶段进行字段添加:

  • 第一阶段:添加字段,但暂不使用新字段。
  • 第二阶段:逐步在应用中实施使用新字段的代码。
  • 第三阶段:在确认新字段稳定运行后,清理或迁移旧数据。

5. 使用在线DDL工具

对于MySQL用户,可以考虑使用诸如pt-online-schema-change这类工具,它可以在不锁表的情况下进行表结构的变更。这对于需要24/7运行的应用尤为重要。

行锁

MySQL的行锁是在引擎层由各个引擎自己实现的。但并不是所有的引擎都支持行锁,比如MyISAM引擎就不支持行锁。不支持行锁意味着并发控制只能使用表锁,对于这种引擎的表,同一张表上任何时刻只能有一个更新在执行,这就会影响到业务并发度。InnoDB是支持行锁的,这也是MyISAM被InnoDB替代的重要原因之一。

特点: 在InnoDB事务中,行锁是在需要的时候才加上的,要等到事务结束时才释放。这个就是两阶段锁协议

使用:将最经常修改的数据放到最后提交,能最大程度减少锁等待

死锁

定义:并发系统中不同线程出现循环资源依赖,涉及的线程都在等待别的线程释放资源时,就会导致这几个线程都进入无限等待的状态

解决方法

  1. 直接进入等待,直到超时,相关参数为:innodb\_lock\_wait\_timeout 默认值为50s
  2. 正常情况下采用:发起死锁检测,主动回滚某一个事务,相关参数:innodb\_deadlock\_detect默认值为on

在秒杀情况下,可以采取如下方法

  1. 临时关闭死锁检测,但是带有风险性
  2. 控制并发度,使用中间件,或者直接修改源码
  3. 将一条记录分为多条,但需要注意临界值处理

普通索引和唯一索引的选择

索引基础

在数据库设计中,普通索引唯一索引是两种常见的索引类型,它们在应用时会根据业务需求和数据的特性来选择。普通索引允许索引列包含重复的值,而唯一索引则保证索引列的值全局唯一。

业务场景分析

例如,一个市民系统中,每个人的身份证号都是唯一的。如果系统需要通过身份证号查询个人信息,可以在id_card字段上建立索引。这里存在两个选择:

  1. 普通索引:如果业务层已经保证了身份证号的唯一性,普通索引可以有效支持查找操作。
  2. 唯一索引:额外保证数据的唯一性,防止由于错误或漏洞导致重复数据的插入。

性能考量

  • 查询性能:唯一索引和普通索引在查找数据时的性能差异微乎其微,因为InnoDB存储引擎的数据管理是基于数据页的,即使是普通索引在达到查询条件后的额外检索操作,也仅涉及内存中的简单计算。
  • 更新性能:普通索引可以使用change buffer优化更新操作,尤其是当数据页不在内存中时。唯一索引需要检查唯一性约束,因此不能使用change buffer,可能导致更频繁的磁盘I/O。

实践建议

在选择普通索引还是唯一索引时,应该根据以下几点考虑:

  • 数据唯一性需求:如果业务规则或逻辑已经确保了数据的唯一性,普通索引可能足够且更灵活。如果需要数据库层面的严格数据唯一性保证,应选择唯一索引。
  • 性能需求:普通索引在某些更新操作中可能更高效,尤其是在涉及大量写操作的场景中。
  • 系统资源:考虑系统的内存和存储资源,普通索引的change buffer特性可能对系统性能有正面影响。

索引及其选择机制

MySQL中的表可以有多个索引,而使用哪个索引进行查询优化通常由MySQL的查询优化器自动决定。优化器的目标是选择最小化查询成本的执行计划。

索引选择错误的示例

在文档中提供了一个实验案例:

  • 创建一个简单的表t,包含字段ab,并为这两个字段各自创建索引。
  • 向表中插入100000行数据,其中ab字段的值从1递增到100000。
  • 执行查询select * from t where a between 10000 and 20000,理论上应优先使用索引a
问题出现的条件

在对表进行大量数据删除和再次插入操作后,查询优化器未能选择最佳索引a,而是进行了全表扫描,导致查询性能显著下降。

优化器逻辑与决策因素
  • 扫描行数:优化器评估不同索引方案的扫描行数,越少的扫描行数通常意味着越高的查询效率。
  • 其他因素:是否需要使用临时表、是否需要排序等,也会影响优化器的索引选择。
索引的区分度和基数
  • 区分度:索引的区分度高意味着通过该索引能更有效地过滤数据。

  • 基数:索引的基数是指索引列上不同值的数量。基数的准确性直接影响优化器的选择准确性。
    索引选择错误的原因

  • 索引的“区分度”和“基数”是优化器决定是否使用某个索引的关键。

  • 基数的计算是通过采样统计得出的,这可能导致不精确的结果。

  • 采样统计:为了减少计算资源消耗,MySQL通过采样部分数据来估计整个表的索引基数。

统计信息的角色

MySQL通过对表的一部分数据进行采样,来估算索引的基数。若数据分布发生变化(如频繁的插入和删除操作),采样得到的统计信息可能不再准确,从而影响优化器的索引选择。

解决方案和实践建议
  • 强制索引使用:通过force index语句可以强制查询优化器使用特定索引。
  • 监控和调整:通过设置long_query_time为0并检查慢查询日志,可以识别并分析由于索引选择不当导致的低效查询。
  • 维护统计信息:定期更新表的统计信息,以保持优化器决策的准确性,特别是在数据变动频繁的表上。

结论

在MySQL数据库管理和优化中,理解并正确处理索引选择问题至关重要。优化器虽然大多数时间能自动选择最优索引,但在特定情况下(如数据频繁更新时)也可能出错。开发者需要掌握相关知识和技巧,以确保数据库查询的性能和效率。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/9238.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【C++ list所有函数举例如何使用】

C 中的 std::list 是一个双向链表&#xff0c;提供了在列表中添加、删除、访问元素等操作的方法。以下是一些常用的 std::list 函数以及如何使用它们的示例&#xff1a; push_back(const T& value): 在列表的末尾添加一个值为 value 的元素。 std::list<int> mylis…

Faiss核心解析:提升推荐系统的利器【AI写作免费】

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

STM32使用L9110驱动电机自制小风扇

1.1 介绍&#xff1a; 该电机控制模块采用L9110电机控制芯片。该芯片具有两个TTL/CMOS兼容输入端子&#xff0c;并具有抗干扰特性&#xff1a;具有高电流驱动能力&#xff0c;两个输出端子可直接驱动直流电机&#xff0c;每个输出端口可提供750800mA动态电流&#xff0c;其峰值…

【适用全主题】WordPress原创插件:弹窗通知插件 支持内容自定义

内容目录 一、详细介绍二、效果展示1.部分代码2.效果图展示 三、学习资料下载 一、详细介绍 适用于所有WordPress主题的弹窗插件 一款WordPress原创插件&#xff1a;弹窗通知插件 支持内容自定义 二、效果展示 1.部分代码 代码如下&#xff08;示例&#xff09;&#xff1…

【GoLang基础】map是什么?

问题引出&#xff1a; Go语言中map是什么&#xff1f; 解答&#xff1a; map 是一种集合型数据结构&#xff0c;用于存储键值对&#xff0c;并提供了快速的查找、插入和删除操作。以下是更深入的介绍和使用 map 的注意事项&#xff1a; 1. 声明和初始化 在 Go 中声明和初始化…

【java.io.IOException: java.lang.IllegalArgumentException: db.num is null】

默认用户名&#xff1a;nacos 密码&#xff1a;nacos解决方法&#xff1a; a)在conf目录下将nacos-mysql.sql脚本创建完成&#xff1b; b)修改application.properties&#xff0c;在内容里添加如下内容 spring.datasource.platformmysql db.num1 db.url.0jdbc:mysql://localho…

网络安全零信任学习2:零信任概念

《白话零信任》第2章&#xff1a; 零信任假设最坏的情况已经发生&#xff0c;一切都不可信&#xff0c;在此基础上执行 最严格的动态持续认证和访问控制策略。 &#xff08;1&#xff09;网络不可信&#xff1a;网络始终充满威胁&#xff0c;内网与外网没有不同&#xff0c;网络…

有刷电机、无刷电机

阅读引言&#xff1a; 最近在备赛&#xff0c; 自己之前虽然用过电机&#xff0c; 但是发现在一些高要求的应用场景&#xff0c; 发现自己对电机的知识理解得不是很透彻&#xff0c; 所以写下这篇文章。 目录 一、 有刷电机内部原理 二、有刷电机一些关键参数 三、无刷电机内…

2024OD机试卷-英文输入法 (java\python\c++)

题目:英文输入法 题目描述 主管期望你来实现英文 输入法 单词联想功能。 需求如下: 依据用户输入的单词前缀,从已输入的英文语句中联想出用户想输入的单词,按字典序输出联想到的单词序列, 如果联想不到,请输出用户输入的单词前缀。 注意: 英文单词联想时,区分大小写缩…

机器学习初学者 6 个核心算法!建议收藏,反复观看!

今天再来介绍机器学习算法的基本概念和适用场景&#xff01; 首先&#xff0c;引用一句英国统计学家George E. P. Box的名言&#xff1a;All models are wrong, but some are useful. 没有哪一种算法能够适用所有情况&#xff0c;只有针对某一种问题更有用的算法。 也就是说&…

STM32理论 —— μCOS-Ⅲ(新)

文章目录 1. 任务调度器1.1 抢占式调度 μCos-Ⅲ全称是Micro C OS Ⅲ&#xff0c;由Micriμm 公司发布的一个基于C 语言编写的第三代小型实时操作系统(RTOS)&#xff1b; RTOS 与裸机相比最大的优势在于多任务管理与实时性&#xff0c;它提供了多任务管理和任务间通信的功能&a…

scala案例-- 九九乘法表

要求&#xff1a;打出九九乘法表 object test {def main(args: Array[String]): Unit {for (i <- 1 to 9) { //外循环控制行数for (j <- 1 to i) { //内循环控制列数print(s"${j} * ${i} ${i j}\t")}println()}} }结果&#xff1a; 1 * 1 2 1 * 2 …

一文玩转Vue3参数传递——全栈开发之路--前端篇(8)

全栈开发一条龙——前端篇 第一篇&#xff1a;框架确定、ide设置与项目创建 第二篇&#xff1a;介绍项目文件意义、组件结构与导入以及setup的引入。 第三篇&#xff1a;setup语法&#xff0c;设置响应式数据。 第四篇&#xff1a;数据绑定、计算属性和watch监视 第五篇 : 组件…

电脑桌面定时提醒软件 有定时提醒功能的软件有哪些

对于很多上班族来说&#xff0c;在电脑、手机上使用一款定时提醒软件&#xff0c;是非常有必要的。一款定时提醒软件能让我们对即将进行的工作一目了然&#xff0c;防止遗漏或错过重要事务。其次&#xff0c;通过设定提醒&#xff0c;我们可以更好地安排自己的时间&#xff0c;…

基于springboot实现医院药品管理系统项目【项目源码+论文说明】

基于springboot实现医院药品管理系统演示 摘要 身处网络时代&#xff0c;随着网络系统体系发展的不断成熟和完善&#xff0c;人们的生活也随之发生了很大的变化&#xff0c;人们在追求较高物质生活的同时&#xff0c;也在想着如何使自身的精神内涵得到提升&#xff0c;而读书就…

图书管理系统c语言

创建一个图书管理系统是一个涉及数据结构和文件操作的项目。在C语言中&#xff0c;你可以使用结构体来表示图书信息&#xff0c;使用函数来实现系统的各项功能。以下是一个简单的图书管理系统的示例&#xff0c;包括基本的添加、显示、查找和删除图书的功能。 1. 定义图书结构…

社交媒体数据恢复:新浪微博

当我们在使用新浪微博时&#xff0c;可能会遇到一些意外情况&#xff0c;如误删微博、账号出现问题等。这时&#xff0c;我们需要进行数据恢复。本文将详细介绍如何在新浪微博中进行数据恢复。 首先&#xff0c;我们需要了解新浪微博的数据恢复功能。根据微博的帮助中心&#…

Android11 InputManagerService启动流程分析

InputManagerService在systemserver进程中被启动 //frameworks\base\services\java\com\android\server\SystemServer.java t.traceBegin("StartInputManagerService"); inputManager new InputManagerService(context);//1 t.traceEnd(); //省略 //注册服务 Servi…

Spring Data JPA进行数据库操作

使用Spring Data JPA进行数据库操作涉及几个关键步骤&#xff0c;包括配置、定义实体类、创建仓库接口以及执行具体的数据库操作。以下是详细的过程&#xff1a; 1. 添加依赖 首先&#xff0c;在项目的pom.xml文件中添加Spring Data JPA的依赖&#xff1a; <dependencies…

socket实现TCP UDP

1、socket通信建立流程 1.1、创建服务端流程 使用 socket 函数来创建 socket服务。 使用 bind 函数绑定端口。 使用 listen 函数监听端口。 使用 accept 函数接收客户端请求。 1.2、创建客户端流程 使用 socket 函数来创建 socket 服务。 使用 connect 函数连接到 socke…