对MySQL索引、锁及事务的简单分析

时间:2022-09-24 09:13:07

一.索引的数据结构

  1.二叉搜索树实现的索引

    二叉搜索树如下图,它查找元素的时间复杂度为O(logn)

    对MySQL索引、锁及事务的简单分析

    但如果经常出现增删操作,最后导致二叉搜索树变成线性的二叉树,这样它查找元素的时间复杂度就会变成O(n),如图

    对MySQL索引、锁及事务的简单分析

    虽然可以通过树的旋转来保证该树是一个平衡二叉树(左右子树深度之差的绝对值不大于1),但磁盘的IO次数会变多,并不是最优方案

  2.B-Tree实现的索引

    B-Tree(B树)是为磁盘等外存储设备设计的一种平衡查找树,它可以让系统高效的找到数据所在的磁盘块。

    为了描述B-Tree,首先定义一条记录为一个二元组[key, data] ,key为记录的键值,对应表中的主键值,data为一行记录中除主键外的数据。对于不同的记录,key值互不相同。B-Tree中的每个节点根据实际情况可以包含大量的关键字信息和分支,如下图所示为一个3阶的B-Tree:

    对MySQL索引、锁及事务的简单分析

    

    每个节点占用一个盘块的磁盘空间,一个节点上有两个升序排序的关键字和三个指向子树根节点的指针,指针存储的是子节点所在磁盘块的地址。两个关键词划分成的三个范围域对应三个指针指向的子树的数据的范围域。以根节点为例,关键字为17和35,P1指针指向的子树的数据范围为小于17,P2指针指向的子树的数据范围为17~35,P3指针指向的子树的数据范围为大于35。

    模拟查找关键字29的过程:

      1.根据根节点找到磁盘块1,读入内存。【磁盘I/O操作第1次】

      2.比较关键字29在区间(17,35),找到磁盘块1的指针P2。

      3.根据P2指针找到磁盘块3,读入内存。【磁盘I/O操作第2次】

      4.比较关键字29在区间(26,30),找到磁盘块3的指针P2。

      5.根据P2指针找到磁盘块8,读入内存。【磁盘I/O操作第3次】

      6.在磁盘块8中的关键字列表中找到关键字29。

    分析上面过程,发现需要3次磁盘I/O操作,和3次内存查找操作。由于内存中的关键字是一个有序表结构,可以利用二分法查找提高效率。而3次磁盘I/O操作是影响整个B-Tree查找效率的决定因素。B-Tree相对于AVLTree(平衡二叉树)缩减了节点个数,使每次磁盘I/O取到内存的数据都发挥了作用,从而提高了查询效率。但由于树的每个节点能存放的数据是有限的,因此,当数据量大的时候可能会导致B树的深度变大,影响查询效率和磁盘IO次数。

  3.B+-Tree实现的索引

    B+树是应文件系统所需而产生的一种B树的改进方式(文件的目录一级一级索引,只有最底层的叶子节点(文件)保存数据),即非叶子节点只保存索引,不保存实际的数据,数据都保存在叶子节点中。如下图为一个B+树结构图

    对MySQL索引、锁及事务的简单分析

    对于索引的性能,不仅仅要考虑时间复杂度,还要考虑磁盘的IO次数,因而,B+树比B树有以下优势:

    (1)B+树的磁盘读写代价更低:B+树的内部节点并没有指向关键字具体信息的指针,因此其内部节点相对B树更小,如果把所有同一内部节点的关键字存放在同一盘块中,那么盘块所能容纳的关键字数量也越多,一次性读入内存的需要查找的关键字也就越多,相对IO读写次数就降低了。

    (2)B+树的查询效率更加稳定:由于非终结点并不是最终指向文件内容的结点,而只是叶子结点中关键字的索引。所以任何关键字的查找必须走一条从根结点到叶子结点的路。所有关键字查询的路径长度相同,导致每一个数据的查询效率相当。

    (3)B+树更有利于对数据库的扫描:由于数据存放在叶子节点,所以遍历全部叶子节点即可获取全部数据

  PS:MySQL的MyISAM、InnoDB引擎默认均使用B+树索引

  4.Hash实现的索引

    由于Hash实现索引的方式可以直接通过Hash算法定位到特定值的位置,因此有些情况它的效率比B+树还高。

    但Hash实现的索引缺点也很明显:

      不能使用范围查询

      不能进行排序运算

      不能避免表扫描

      遇到大量Hash值相等的情况下,效率就会变得低下(不稳定)

二.索引的类别及数据库中索引的相关操作

  索引可以分为密集索引和稀疏索引两大类

    对于MyISAM引擎,不管是主键索引,唯一索引或普通索引,均属于稀疏索引

    对于InnoDB,如果一个主键被定义,该主键则为密集索引,若没有主键被定义,则该表的第一个唯一非空索引则作为密集索引,若不满足前两个条件,InnoDB内部会生成一个隐藏主键(密集索引)

  索引的创建方式

CREATE INDEX indexName ON TABLENAME(username(length));

    或创建表的时候指定

CREATE TABLE TABLENAME(
ID INT NOT NULL,
username VARCHAR(16) NOT NULL,
INDEX [indexName] (username(length))
);

    或使用ALTER 命令添加

ALTER TABLE tbl_name ADD PRIMARY KEY (column_list): 该语句添加一个主键,这意味着索引值必须是唯一的,且不能为NULL。
ALTER TABLE tbl_name ADD UNIQUE index_name (column_list): 这条语句创建索引的值必须是唯一的(除了NULL外,NULL可能会出现多次)。
ALTER TABLE tbl_name ADD INDEX index_name (column_list): 添加普通索引,索引值可出现多次。
ALTER TABLE tbl_name ADD FULLTEXT index_name (column_list):该语句指定了索引为 FULLTEXT ,用于全文索引。

  索引的删除方式

DROP INDEX [indexName] ON TABLENAME; 

    或

ALTER TABLE testalter_tbl DROP INDEX c;

  创建联合索引及联合索引最左匹配原则

ALTER TABLE projectfile ADD INDEX (ids, names);

    查询中我们能用到的索引的是ids和ids names,而仅仅查询names是不会用到该索引的

三.慢查询

  可以通过下面两条命令查看慢查询相关信息:

SHOW VARIABLES LIKE '%quer%';#查询相关变量
SHOW STATUS LIKE '%slow_queries%';#查询慢查询的数量

  例如下图

  对MySQL索引、锁及事务的简单分析

  开启慢查询日志:

SET GLOBAL slow_query_log=ON;#开启慢查询日志

  设置慢查询默认时间:

SET GLOBAL long_query_time=1;#设置慢查询默认时间(需要重新连接才生效,且重启服务后失效,如果需要永久开启慢查询日志和设置慢查询一些属性,可以在配置文件中修改)

  我们常常用到explain这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句有没有使用上了索引,有没有做全表扫描等等,这都可以通过explain命令来查看,例如

  对MySQL索引、锁及事务的简单分析

四.MySQL中引擎和锁

  MyISAM默认用的是表级锁,不支持行级锁,而InnoDB默认用的是行级锁,也支持表级锁。

  通过以下代码即可查看数据库中引擎使用情况

SHOW ENGINES;

  对MySQL索引、锁及事务的简单分析

  1.MyISAM引擎:

    当有某个表中有数据正在被读取的时候,MyISAM会自动给整个表加上一个读锁,当有数据在被增删改的时候,MyISAM会自动给整个表加上一个写锁。当读锁未被释放的时候,写锁会被阻塞,无法对该表进行增删改,直到所有的读锁释放。同理,写锁未被释放时,读取数据的操作会被阻塞,不仅如此,一个写锁未释放,其他写锁也会被阻塞。因此,读锁也被称为共享锁,写锁也称为排他锁/互斥锁。

    手动给表添加读锁或写锁:

LOCK TABLES users READ;
LOCK TABLES users WRITE;

    手动解锁:

UNLOCK TABLES;

    MyISAM适用场景:

      频繁执行全表count语句

      对数据进行增删改频率不高,查询非常频繁

      没有事务的场景

  2.InnoDB引擎:

    InnoDB支持事务和行级锁,而MySQL默认是提交事务的,对事务添加共享锁,在sql后添加如下代码

LOCK IN SHARE MODE

    InnioDB对某些行加了共享锁,但是可以对其他行加排他锁;同理,对某些行加排他锁后还可以对其他行加共享锁或排他锁,这就是行级锁特性。但行级锁会比表级锁更消耗性能

    InnoDB使用场景:

      数据增删改查都相当频繁

      可靠性要求比较高要求支持事务的场景

  3.乐观锁

    总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现。

    乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库提供的类似于write_condition机制,其实都是提供的乐观锁。在Java中java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一种实现方式CAS实现的。

    关于CAS算法:

      1、对于资源竞争较少(线程冲突较轻)的情况,使用synchronized同步锁进行线程阻塞和唤醒切换以及用户态内核态间的切换操作额外浪费消耗cpu资源;而CAS基于硬件实现,不需要进入内核,不需要切换线程,操作自旋几率较少,因此可以获得更高的性能。

      2、对于资源竞争严重(线程冲突严重)的情况,CAS自旋的概率会比较大,从而浪费更多的CPU资源,效率低于synchronized。

  4.悲观锁

    总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁。

    悲观锁适用于多写的场景,以上的共享锁和排他锁,它们都属于悲观锁。

五.MySQL中的事务

  可以通过下列代码查询数据库使用的事务隔离级别

SELECT @@tx_isolation;

  可以通过下列代码开启事务

START TRANSACTION;

  可以通过下列代码修改事务隔离级别

SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITED;#修改事务隔离级别未读已提交,也可以是其他级别

  事务的隔离级别:(设置的隔离级别越高越影响数据库性能)

    读未提交

    读已提交

    可重复读

    串行化

  事务并发访问可能引发的问题:

    更新丢失(一个修改覆盖另一个修改):例如一个事务A修改了某行数据,而其他事务B也修改了该行数据。MySQL的锁机制可以解决该问题。

    脏读(一个事务读到另一个事务未提交的数据):例如一个事务A修改了某行数据,但是未提交,而是回滚了,而其他一个事务B获取该事务修改后却回滚的数据,从而产生问题。将事务隔离级别设置在读已提交之上可以解决该问题。

    不可重复度(多次读取同一数据,结果不一致):例如一个事务A一直读取某行数据,但有其他事务B对该行数据进行了修改,事务A发现读取的数据不一致,从而产生数据不可靠问题。将事务隔离级别设置在可重复读之上可以解决该问题(保证读的数据一致)。

    幻读(读取到不存在的数据,或读取到的数据消失了):例如一个事务A读取发现数据X不存在,但事务B添加了数据X,事务A发现X凭空产生了(与不可重复读很像,但它强调的是插入和删除数据)。将事务隔离级别设置在串行化可以解决该问题。在快照读读情况下,通过MVCC来避免幻读。在当前读读情况下,通过next-key来避免幻读。

对MySQL索引、锁及事务的简单分析的更多相关文章

  1. day 59 MySQL之锁、事务、优化、OLAP、OLTP

    MySQL之锁.事务.优化.OLAP.OLTP   本节目录 一 锁的分类及特性 二 表级锁定(MyISAM举例) 三 行级锁定 四 查看死锁.解除锁 五 事务 六 慢日志.执行计划.sql优化 七 ...

  2. MySql 三大知识点,索引、锁、事务,原理分析

    1.索引 索引,类似书籍的目录,可以根据目录的某个页码立即找到对应的内容. 索引的优点:1. 天生排序,2. 快速查找. 索引的缺点:1. 占用空间,2. 降低更新表的速度. 注意点:小表使用全表扫描 ...

  3. Mysql之锁、事务绝版详解---干货!

    一 锁的分类及特性 数据库锁定机制简单来说,就是数据库为了保证数据的一致性,而使各种共享资源在被并发访问变得有序所设计的一种规则.对于任何一种数据库来说都需要有相应的锁定机制,所以MySQL自然也不能 ...

  4. MySQL之锁、事务、优化、OLAP、OLTP

    本节目录 一 锁的分类及特性 二 表级锁定(MyISAM举例) 三 行级锁定 四 查看死锁.解除锁 五 事务 六 慢日志.执行计划.sql优化 七 OLTP与OLAP的介绍和对比 八 关于autoco ...

  5. mysql的锁与事务

    1. MySQL中的事物 1.InnoDB事务原理 1. 事务(Transaction)是数据库区别于文件系统的重要特性之一,事务会把数据库从一种一致性状态转换为另一种一致性状态. 2. 在数据库提交 ...

  6. Mysql 数据锁与事务

    一.锁 常用命令 查看表的存储引擎:mysql> show create table myLock; 修改当前表的存储引擎:mysql> alter table myLock engine ...

  7. mysql InnoDB锁等待的查看及分析

    说明:前面已经了解了InnoDB关于在出现锁等待的时候,会根据参数innodb_lock_wait_timeout的配置,判断是否需要进行timeout的操作,本文档介绍在出现锁等待时候的查看及分析处 ...

  8. MySql锁和事务隔离级别

    在讲mysql事物隔离级别之前,我们先简单说说mysql的锁和事务. 一:数据库锁 因为数据库要解决并发控制问题.在同一时刻,可能会有多个客户端对同一张表进行操作,比如有的在读取该行数据,其他的尝试去 ...

  9. 五分钟搞懂MySQL索引下推

    大家好,我是老三,今天分享一个小知识点--索引下推. 如果你在面试中,听到MySQL5.6"."索引优化" 之类的词语,你就要立马get到,这个问的是"索引下推 ...

随机推荐

  1. GIT的认识

    说实话,在听到小伙伴们都说赶紧做作业的时候很茫然,连一点头绪都没有,根本不知道从何入手,但不能因为不会就不去做,于是还是拿起手机,找到小伙伴商量着做着,虽然等的过程很焦急,但还是注册成功了.而开始写对 ...

  2. 【python】类中的self

    在python的类中,经常会写self,代表对象自己.如下例: #coding=utf-8 class Foo: def __init__(self, name): self.name = name ...

  3. java.util.concurrent.CountDownLatch

    闭锁是一种同步工具类,可以延迟线程的进度直到闭锁到达终止状态. 闭锁的作用相当于一扇门,在闭锁到达结束状态之前,这扇门一直是关闭的,任何线程都不能通过这扇门,当闭锁到达结束状态时,这扇门会打开并允许所 ...

  4. java 分布式id生成算法

    import java.lang.management.ManagementFactory; import java.net.InetAddress; import java.net.NetworkI ...

  5. 可视化布局html5

    http://www.bootcss.com/p/layoutit/ http://layuiout.magicalcoder.com/magicaldrag-admin/drag

  6. Docker 微服务教程(搭建真正的网站)

    Docker 是一个容器工具,提供虚拟环境.很多人认为,它改变了我们对软件的认识. 站在 Docker 的角度,软件就是容器的组合:业务逻辑容器.数据库容器.储存容器.队列容器......Docker ...

  7. 4. 多重背包问题 I

    多重背包问题 I 描述 有 NN 种物品和一个容量是 VV 的背包. 第 ii 种物品最多有 sisi 件,每件体积是 vivi,价值是 wiwi. 求解将哪些物品装入背包,可使物品体积总和不超过背包 ...

  8. virtual judge 本地部署方案

    这是一种将自己的电脑当作服务器来部署一个vj的方法,我也是参考前辈们的做法稍作了改动,如果在服务器上部署的话需要在细节上稍作改动: 一.什么是Virtual Judge? vj的工作原理什么?  vj ...

  9. Python基础--字典:当索引不好用时

    当列表或是元组的索引不能达到我们的目的时,我们想到了还有一种序列,即字典. 创建 字典 由多个键以及相应的值构成的键-值对组成. 键唯一.值能够不唯一 phonebook = {'xidada':'1 ...

  10. JS高程3:JSON

    JSON,JavaScript Object Notation,JS对象表示法,是目前最常见的传输结构化数据的数据结构. JSON并非编程语言,而是一种数据结构,像mp4.avi一样,只是一种数据格式 ...