数据库系列:MySQL慢查询分析和性能优化

数据库系列:MySQL索引优化总结(综合版)

数据库系列:高并发下的数据字段变更

数据库系列:覆盖索引和规避回表

数据库系列:数据库高可用及无损扩容

数据库系列:使用高区分度索引列提升性能

数据库系列:前缀索引和索引长度的取舍

数据库系列:MySQL引擎MyISAM和InnoDB的比较

数据库系列:InnoDB下实现高并发控制

数据库系列:事务的4种隔离级别

数据库系列:RR和RC下,快照读的区别

1 背景

随着互联网的发展,高并发业务的盛行,MySQL InnoDB引擎的细粒度行锁,变成很核心的特性之一。

在并发高的情况下,如果使用不当,会导致严重的性能问题。比如细粒度行锁,是实现在索引记录上的,但如果没有命中索引,就回退化成表锁,那对性能是灾难的。

下面我们从索引角度出发, 介绍下MySQL InnoDB的锁机制。

2 InnoDB的索引回顾

Innodb中有2种索引:主键索引(也叫聚集索引 Clustered Index)、辅助索引(也叫非聚集索引 Secondary Index)。

主键索引: 每个表只有一个主键索引,b+树结构,叶子节点存储主键的值以及对应整条记录的数据,非叶子节点不存储记录的数据,只存储主键的值。

当表中未指定主键时,MySQL内部会自动给每条记录添加一个隐藏的rowid字段(默认4个字节)作为主键,用rowid构建聚集索引。聚集索引在MySQL中即主键索引。

辅助索引: 每个表可以有多个辅助索引,b+树结构,非聚集索引叶子节点存储字段(索引字段)的值以及对应记录主键的值,其他节点只存储字段的值(索引字段),这就是与聚集索引不同的地方。每个表可以有多个非聚集索引。

InnoDB的每一个表都会有聚集索引:

  • 假设表定义了PK,则PK就是聚集索引
  • 如果未定义PK,则第一个非空unique列即是聚集索引
  • 如果没有PK也没有非空unique列,InnoDB会创建一个隐含的row_id作为聚集索引使用

下图更形象说明这两种索引的区别,这边假设了一个存储4行数据的表。Id为主键索引,Name作为辅助索引,图中清晰的体现了聚簇索引和非聚簇索引的差异。

表中有四条记录:

5, Gates, Microsoft
7, Bezos, Amazon
11, Jobs, Apple
14, Elison, Oracle

InnoDB数据检索过程

上面的表中有2个索引:id作为主键索引,name作为辅助索引。

如果需要查询id=14的数据,只需要在左边的主键索引中检索就可以了。

如果需要搜索name='Ellison'的数据,需要2步:

  1. 先在辅助索引中检索到name='Ellison'的数据,获取id为14
  2. 再到主键索引中检索id为14的记录

    辅助索引这个查询过程在mysql中叫做回表,相对于主键索引多了第二步操作。

MyISAM数据检索过程

  1. 在索引中找到对应的关键字,获取关键字对应的记录的地址
  2. 通过记录的地址查找到对应的数据记录

对比发现:Innodb中最好是采用主键索引查询,这样只需要一次索引,如果使用辅助索引检索,涉及多一步的回表操作,比主键查询要耗时一些。

所以,InnoDB的普通索引,实际上会扫描两遍:

第1遍,由普通索引找到PK:检索到name='Ellison'的数据,获取id为14

第2遍,由PK找到行记录:即到主键索引中检索id为14的记录

对索引有兴趣的,可以参考作者的这几篇文章:

MySQL全面瓦解22:索引的介绍和原理分析

MySQL全面瓦解23:MySQL索引实现和使用

MySQL全面瓦解24:构建高性能索引(策略篇)

3 InnoDB 几种常见锁

★InnoDB默认的事务隔离级别为可重复读(Repeated Read, RR),我们当下的所有介绍都是基于这个隔离级别为前提的。

  • 记录锁(Record Locks):锁定单一行记录,InnoDB 使用记录锁来实现行级锁,这样允许多个事务并发访问不同的行。
  • 间隙锁(Gap Locks):InnoDB 的特性,用于锁定一个范围,但不包括实际的记录。这主要用于防止幻读(Phantom Reads)。
  • 临键锁(Next-Key Locks):InnoDB 存储引擎的一种锁定机制,在执行查询语句时,根据查询条件所锁定的一个范围。这个范围中包含有间隙锁和记录锁。它的设计目的是为了解决幻读(Phantom Reads)。

3.1 记录锁(Record Locks)

记录锁,它封锁索引记录,例如:

select * from table where id=5 for update;

它会在id=1的索引记录上加锁,以阻止其他事务插入,更新,删除id=1的这一行。

需要说明的是:

select * from table where id=5;

则是快照读(SnapShot Read),它并不加锁,快照读可以参考作者这篇文章:数据库系列:RR和RC下,快照读的区别

3.2 间隙锁(Gap Locks)

间隙锁,它封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一条索引记录之后的范围。

延续上面的那个例子继续演示:

# 表结构
table (Id PK, Name , Company); # 表中包含四条记录
5, Gates, Microsoft
7, Bezos, Amazon
11, Jobs, Apple
14, Elison, Oracle

执行SQL语句如下:

select * from table
where id between 7 and 13
for update;

这样的话,会封锁数据的区间,以防止其他事务插入id=8的记录。

假设没有间隙锁,则可能够插入成功,而之前的select事务,会发现检索的结果集莫名多了一条记录,即幻影数据。

所以间隙锁主要目的用于防止幻读(Phantom Reads),避免其他事务在间隔中插入数据,导致 『不可重复读』。

如果把事务的隔离级别降级为读提交(Read Committed, RC),对,就是互联网最常用的隔离级别,间隙锁则会自动失效。

3.3 临键锁(Next-Key Locks)

临键锁(Next-Key Locks)是数据库管理系统InnoDB中的一种重要锁定机制。这种锁是查询时根据查询条件锁定的一个范围,这个范围包括间隙锁和记录锁,左开右闭,即不锁住左边界,但会锁住右边界。临键锁的主要设计目的是为了解决所谓的“幻读”问题。

# 左开右闭 示例
(-infinity, 1]
(1, 7]
(7, 9]
(9, +infinity]

依然沿用上面的例子,InnoDB引擎,RR隔离级别:

-- 创建一个示例表
CREATE TABLE users (
Id INT PRIMARY KEY,
Name VARCHAR(255) NOT NULL,
Company VARCHAR(255) NOT NULL,
); -- 插入一些示例数据
INSERT INTO users (id, name, company) VALUES (1, 'Alice', 'ali');
INSERT INTO users (id, name, company) VALUES (2, 'Brand', 'tencent');
INSERT INTO users (id, name, company) VALUES (3, 'Charlie', 'baidu'); -- 开始一个事务,并使用临键锁查询数据
START TRANSACTION;
SELECT * FROM users WHERE id > 1 FOR UPDATE; -- 在另一个事务中尝试插入新数据,将会被阻塞直到第一个事务释放锁
START TRANSACTION;
INSERT INTO users (id, name, age) VALUES (4, 'David', 30);
COMMIT; -- 第一个事务提交后,第二个事务可以继续执行插入操作
COMMIT;

临键锁的主要目的,也是为了避免幻读(Phantom Read),在事务隔离级别为可重复读的情况下,InnoDB存储引擎默认使用临键锁。这种锁提供了一种有效的机制来保证在并发环境中数据的完整性和一致性。

如果把事务的隔离级别降级为RC,临键锁则也会失效。

4 总结

  • InnoDB的索引与行记录存储在一起,MyISAM则是通过索引的地址查找到对应的数据记录,效率低一些
  • InnoDB的聚集索引存储行记录,普通索引存储PK,所以普通索引要查询两次
  • 记录锁锁定索引关联的具体记录
  • 间隙锁锁定间隔,防止间隔中被其他事务插入
  • 临键锁锁定索引记录+间隔,防止幻读
  • elect...for update加锁的几种情况:
    • 主键字段:加行锁。
    • 唯一索引字段:加行锁。
    • 普通索引字段:加行锁。
    • 主键范围:加多个行锁。
    • 普通字段:加表锁。
    • 查询空数据:不加锁。
  • 行锁与表锁的区别
    • 如果事务1加了行锁,一直未释放锁,事务2操作相同记录,会一直等待直至超时。
    • 如果事务1加了表锁,一直未释放锁,事务2无论操作哪一行记录,都会一直等待直到超时

数据库系列:MySQL InnoDB锁机制介绍的更多相关文章

  1. [转载] 数据库分析手记 —— InnoDB锁机制分析

    作者:倪煜 InnoDB锁机制常常困扰大家,不同的条件下往往表现出不同的锁竞争,在实际工作中经常要分析各种锁超时.死锁的问题.本文通过不同条件下的实验,利用InnoDB系统给出的各种信息,分析了锁的工 ...

  2. MySQL InnoDB锁机制

    概述: 锁机制在程序中是最常用的机制之一,当一个程序需要多线程并行访问同一资源时,为了避免一致性问题,通常采用锁机制来处理.在数据库的操作中也有相同的问题,当两个线程同时对一条数据进行操作,为了保证数 ...

  3. MySQL InnoDB锁机制之Gap Lock、Next-Key Lock、Record Lock解析

    MySQL InnoDB支持三种行锁定方式: l   行锁(Record Lock):锁直接加在索引记录上面,锁住的是key. l   间隙锁(Gap Lock):锁定索引记录间隙,确保索引记录的间隙 ...

  4. Mysql Innodb 锁机制

    latch与lock latch 可以认为是应用程序中的锁,可以称为闩锁(轻量级的锁) 因为其要求锁定的时间必须要非常短,若持续时间长,则会导致应用性能非常差,在InnoDB存储引擎中,latch又可 ...

  5. MySQL- InnoDB锁机制

    InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION):二是采用了行级锁.行级锁与表级锁本来就有许多不同之处,另外,事务的引入也带来了一些新问题.下面我们先介绍一点背景知识 ...

  6. MySQL的innoDB锁机制以及死锁处理

    MySQL的nnoDB锁机制 InnoDB与MyISAM的最大不同有两点:一是支持事务(TRANSACTION):二是采用了行级锁.行级锁与表级锁本来就有许多不同之处,innodb正常的select ...

  7. Mysql锁机制介绍

    Mysql锁机制介绍 一.概况MySQL的锁机制比较简单,其最显著的特点是不同的存储引擎支持不同的锁机制.比如,MyISAM和MEMORY存储引擎采用的是表级锁(table-level locking ...

  8. InnoDB锁机制分析

    InnoDB锁机制常常困扰大家,不同的条件下往往表现出不同的锁竞争,在实际工作中经常要分析各种锁超时.死锁的问题.本文通过不同条件下的实验,利用InnoDB系统给出的各种信息,分析了锁的工作机制.通过 ...

  9. MySQL- 锁机制及MyISAM表锁

    锁是计算机协调多个进程或线程并发访问某一资源的机制.在数据库中,除传统的计算资源(如CPU.RAM.I/O等)的争用以外,数据也是一种供许 多用户 共享的资源.如何保证数据并发访问的一致性.有效性是所 ...

  10. mysql insert锁机制【转】

    最近再找一些MySQL锁表原因,整理出来一部分sql语句会锁表的,方便查阅,整理的不是很全,都是工作中碰到的,会持续更新 笔者能力有限,如果有不正确的,或者不到位的地方,还请大家指出来,方便你我,方便 ...

随机推荐

  1. 交换分区swap的创建与管理

    前言 swap分区是linux系统中一块特殊的硬盘空间,当实际内存不够用的时候,系统会按照一定的算法将部分不用的数据放在swap分区中,从而为当前运行的程序腾出足够的内存空间.好处在于避免内存资源不足 ...

  2. Hugging Face 的文本生成和大语言模型的开源生态

    [更新于 2023 年 7 月 23 日: 添加 Llama 2.] 文本生成和对话技术已经出现多年了.早期的挑战在于通过设置参数和分辨偏差,同时控制好文本忠实性和多样性.更忠实的输出一般更缺少创造性 ...

  3. TCP的可靠性之道:确认重传和流量控制

    TCP 全称为 Transmission Control Protocol(传输控制协议),是一种面向连接的.可靠的.基于字节流的传输层通信协议,其中可靠性是相对于其他传输协议的优势点.TCP 为了确 ...

  4. 系统内存管理:虚拟内存、内存分段与分页、页表缓存TLB以及Linux内存管理

    虚拟内存 虚拟内存是一种操作系统提供的机制,用于将每个进程分配的独立的虚拟地址空间映射到实际的物理内存地址空间上.通过使用虚拟内存,操作系统可以有效地解决多个应用程序直接操作物理内存可能引发的冲突问题 ...

  5. WPF使用TextBlock实现查找结果高亮显示

    在应用开发过程中,经常遇到这样的需求:通过关键字查找数据,把带有关键字的数据显示出来,同时在结果中高亮显示关键字.在web开发中,只需在关键字上加一层标签,然后设置标签样式就可以轻松实现. 在WPF中 ...

  6. Python自定义终端命令

    在python中自定义一个终端命令 这里我们想要将一个csv文件中的数据导入到数据库中,就可以定义一个终端命令,直接一行命令就可以将我们文件中的数据导入到数据库中,特别的简单 首先,我们先创建一个py ...

  7. 全是中文的txt文件查找特定字符并输出该行到新文件

    tangshi.txt文件为全为汉唐诗 在该文件中查找指定字符 codecs库为打开中文文件的库,详情自行知乎 tangshi.txt大概十几万行,需要该文件练手的同学下方评论 要点:更改文件字符编码 ...

  8. RabbitMQ入门实践

    一.概述: 大多应用中,可通过消息服务中间件来提升系统异步通信.扩展解耦能力. 1.消息服务中两个重要概念: 消息代理(message broker)和目的地(destination)当消息发送者发送 ...

  9. Solution -「洛谷 P3773」「CTSC 2017」吉夫特

    Description Link. 求满足 \[\prod _{i=2}^{k} \binom{a_{b_{i-1}}}{a_{b_i}} \mod 2 = \binom{a_{b_1}}{a_{b_ ...

  10. 【python】python开源代理ip池

    一.前言 随着互联网的不断发展,越来越多的应用需要使用高匿代理IP才能访问目标网站,而代理IP作为一种能够隐藏本机真实IP地址的工具,在网络抓取.搜索引擎排名.广告投放.反爬虫等方面有着广泛的应用场景 ...