前言

最近突发新型肺炎,本来只有七天的春节假期也因为各种封锁延长到了正月十五,在家实在闲的蛋疼便重新研究了一下Mysql数据库的相关知识,特此总结梳理一下。本文主要围绕以下几点进行:

1、Mysql的索引与引擎

2、事务隔离级别

3、Mysql的九种锁

4、几点常用规范

一、Mysql的索引与引擎

Mysql最常用的引擎是InnoDB,但还有很多种其他类型的引擎,平时最常用来与它进行比对的是MyISAM。

1、 Mysql是采用B+树作为索引存放的数据结构。B+树结构如下图所示。为什么采用这种类型呢?

因为: M阶的B+树高度不高就能存储大量数据;根据局部性原理,B+树能充分利用磁盘预读,一个叶子节点块存放磁盘读一次的容量;叶子节点用双向链表连接,极大提高了范围查找的速度。

2、Mysql数据库的索引分为两种:主键索引、普通索引 InnoDB的是聚集索引(Clustered Index),MyISAM是非聚集索引(UnClustered Index)

非聚集索引:索引与行记录分开存储。叶子节点存储数据行的地址,定位到叶子节点后再根据地址去找到具体的数据。在非聚集索引下,主键索引和普通索引的实现是一致的,都是非叶子节点存储索引列,叶子节点存储索引列和数据的指针。所以此种情况下可以没有主键索引。

非聚集索引示意图

聚集索引:主键索引与行记录存储在一起,普通索引与主键索引存储在一起。所以InnoDB的主键索引很快,但普通索引走完普通索引的B+树获取到主键索引后还要走一遍主键索引的B+树才能获取到最终的行记录。

所以聚集索引只能有一个且必须要有主键,如果用户未定义主键,则InnoDB会已第一个非空的唯一列作为聚集索引,还不行就会自己创建一个row-id。

二、Mysql的七种锁

1、自增锁

如果表字段中设置了AUTO_INCRUMENT,为保证同一个事务插入数据的递增,在插入时会触发自增锁,阻塞其他事务的插入,它是一种特殊的表级别锁。另外可以通过innodb_autoinc_lock_mode来修改配置。

2、插入意向锁(Insert intention locks)

如果插入的表中没有自增字段,则会使用插入意向锁(间隙锁的一种),即锁定要插入的索引,只要多个事物并发插入时位置不冲突就不会阻塞。

3、意向锁(Intention Locks)

InnoDB允许行级锁与表级锁共存,使用的就是意向锁。意向锁是一个表级别的锁。select * from table where id = 2 lock in share mode; 设置意向共享锁;select * from  table where id = 2 for update; 设置意向排他锁。

意向锁协议:事物要获取某些行的共享锁,需先获取意向共享锁;要获取排他锁,需先获取意向排他锁。

意向锁的共享排他锁之间不互斥,但与普通共享排他锁互斥(只有意向共享锁与普通共享锁可并行)

4、共享/排他锁(Shared and exclusive Locks)

InnoDB中共享/排他锁是标准的行级锁,互斥关系与普通的读写锁一致。

5、记录锁(Record Locks)

锁定指定的索引记录,如select * from table where id = 1 for update;就是记录锁,锁定id=1的这条索引记录

6、间隙锁(Gap Locks)

锁定索引区间,如select * from table where id between 1 and 9 for update;执行后,如果插入id=8的数据会失败。主要目的是防止写导致不可重复读,所以间隙锁也只有在隔离级别是可重复读时生效。

7、临键锁(Next-Key Locks)

可以看成记录锁与间隙锁的组合。它非锁定范围即包含索引记录也包含索引区间。临键锁也是只有在可重复读隔离级别下生效。

三、事务隔离级别

Mysql数据库有四种事务隔离级别(Oracle也是):读未提交(Read Uncommitted)、读提交(Read Committed)、可重复读(Repeated Read)、串行化(Serializable)。Mysql默认是可重复读,但一般都会改成读提交。下面针对读提交和可重复读来看看InnoDB是如何实现的。

1、首先说明一下快照读,Mysql中不带锁普通的sql语句(如select * from table where id < 2)是快照读。普通的读写锁在进行写的时候,读会被堵塞,而mysql针对此情况采用数据多版本,使得在写的时候普通读也不会阻塞。mysql在回滚段(rollback segment)中存放了undo日志,用于记录被事务操作之前事务未提交时数据的old version。这样普通读只要读老版本的数据即可。 此外还有一个redo日志,用于存放事务提交之后的数据。因为每次提交事务后都去刷磁盘,随即写效率低,所以mysql利用类似于缓存的redo日志来临时存放数据,统一往磁盘顺序写,提高吞吐量。

2、在读提交下,select /update/delete *** for update; 采用的是记录锁,即不会锁区间,只是锁匹配到的记录。如果有并发插入会导致幻读。

 3、在可重复读下,select /update/delete *** for update;如果是在唯一索引上使用唯一的查询条件,会使用记录锁,不会锁区间;而如果是范围查询,则使用间隙锁或临键锁,锁住索引记录之间的范围。在此隔离级别下,快照读在事物中第一次调用时mysql会记录一个副本,后续再有读只是从这个副本中读,不会读到之后其他事物提交的改动。

可以看到,InnoDB使用间隙锁和临键锁来避免可重复读下的幻读现象。

四、几个常用规范

1、InnoDB主键不要长了,因为每个普通索引都会存放一遍主键;InnoDB主键必须要设置,并且最好是UNSIGNED整型递增的,这样在插入行时就不会出现大量索引分裂导致数据行换位置;(参见一、2)。

2、必须把字段定义为NOT NULL并设置默认值。

3、where条件禁止用隐性类型转换、函数操作索引行,注意like的最左前缀

最新文章

  1. linux 监测函数
  2. org.springframework.dao.DataIntegrityViolationException:
  3. pm2.5计算和单位换算
  4. css基本设置
  5. CSS样式--实际开发总结
  6. ES6与ES5差别
  7. C# 实现 Snowflake算法 ID生成
  8. HDU 1698 (线段树 区间更新) Just a Hook
  9. 转】Maven学习总结(三)——使用Maven构建项目
  10. jq向上无缝滚动
  11. 实时消息传输协议(RTMP)详解
  12. app.config的坑
  13. jQuery效果之jQuery Color animation 色彩动画扩展
  14. 查看PostgreSQL正在执行的SQL
  15. javascript 20个正则表达式
  16. PHP实现微信申请退款(证书权限必须设为可执行)
  17. scrapy的简单使用
  18. Spark(九)Spark之Shuffle调优
  19. session劫持技术
  20. fastdfs 集群配置

热门文章

  1. dotnet 新项目格式与对应框架预定义的宏
  2. layui图片上传之后后台如何修改图片的后缀名以及返回数据给前台
  3. 【NOIP模拟赛】【数学】完全平方数
  4. C++Review2_代码复用
  5. RobotFramework+Appium 升级Appium v1.10.0后,执行click element时报错:InvalidSelectorException: Message: Locator Strategy &#39;css selector&#39; is not supported for this session,解决办法
  6. bug(一)环境问题
  7. 2019 ICPC南昌网络赛 B题
  8. 组长组Beta阶段贡献分配规则
  9. $vjudge\ CSP-S$专题专练题解
  10. idea编辑器的使用