当前位置:网站首页>MySQL高级(二)

MySQL高级(二)

2022-06-22 18:51:00 追梦的烟火

目录

索引

索引优劣

索引分类

聚簇索引和非聚簇索引

事务

事务特性

隔离级别

事务实现原理

隔离级别实现原理(MVCC)

ReadView

锁机制

Sql优化

索引

为什么要有索引?

索引可以理解为书的目录,通过目录查询效率高。

例如:在数据库中主键默认是添加索引的。

索引是什么?

索引是帮助 mysql 高效获取数据的数据结构,在mysql中使用B+树的

主键:默认添加索引,主键维护在一个B+树中,保存这条记录的物理地址。

索引优劣

优点

可以提高查询效率(使用B+树),把索引数据加载到内存中),减少IO次数;索引使用B+树结构,是有序的,排序时比较快捷方便,减少CPU消耗。

缺点

  • 索引也是需要空间来存储维护的
  • 执行增,删、改操作的时候,需要对索引的结构进行更新

索引分类

主键索引:设置为主键候自动建立索引。

          ALTER TABLE 表名 add PRIMARY KEY 表名(列名);

删除主键索引:

          ALTER TABLE 表名 drop

单值索引/单列索引:一个索引只能包含单个列,一个表可以有多个单列索引。

创建单值索引

      CREATE INDEX 索引名 ON 表名(列名);

删除索引:

        DROP INDEX 索引名

唯一索引:索引列的值必须唯一,允许为null

      CREATE UNIQUE INDEX 索引名 ON 表名(列名);

删除索引:

          DROP INDEX 索引名 ON 表名

组合索引:一个索引包含多个列。

组合索引最左前缀原则: 最左侧索引原则 在使用组合索引时,最左侧的列必须被使用到,否则索引失效。

创建复合索引

         CREATE INDEX 索引名 ON 表名(列 1,列 2...)

删除索引

         DROP INDEX 索引名 ON 表名;

例:

select * from table where a=’’and b=’’ 索引生效
select * from table where b=’’and a=’’ 索引生效
select * from table where a=’’and c=’’ 索引生效
select * from table where b=’’and c=’’ 索引不生效

全文索引:需要模糊查询时,一般索引无效。

CREATE FULLTEXT INDEX 索引名 ON 表名(字段名) WITH PARSER ngram;

SELECT 结构 FROM 表名 WHERE MATCH(列名) AGAINST(搜索词');

查看索引: SHOW INDEX FROM 表名;

索引创建原则

哪些情况下适合添加索引?

  • 主键,默认添加唯一索引

  • 作为查询条件的列

  • 作为外键关联的列

  • 排序的列

  • 分组的列

哪些情况下不适合建立索引?

  • 表记录很少(例如系统参数设置表)

  • 不作为查询条件的列

  • 增删改较为频繁的表,最好为需要的列来添加

  • 数据重复较高的(如性别)

索引的数据结构

mysql使用B+树来存储索引

  • B+树是有序的
  • 每个结点可以存储多个数据(横向扩展)
  • 非叶子节点不存储数据,只存储索引,一个节点中可以存储多个索引
  • 所有的数据存储在叶子节点中,每个叶子节点之间有指针指向

mysql使用B+树的原因?

       有序节省排序时间,一个节点存储多个元素,树的高度降低了,叶子节点之间有指针,便于区间范围查询。

聚簇索引和非聚簇索引

聚簇索引:找到了索引就找到了数据(例如innodb引擎,索引和数据在同一文件中,找到索引就可以找到数据,使用主键作为条件查询,使用其他的列进行查询,查询的结果只有自己)

非聚簇索引:找到了索引,还需要回表进行查询(例如myisam引擎中,索引和数据在两个不同的文件中,找到索引,还需要在存储数据的文件中进行查找)

innodb非聚簇:使用其他列作为查询条件,查询结果除了本列之外还有其他的内容,这种情况需要通过该列先找到主键,在通过主键再次回表查询数据。

事务

概述

事务就是一次数据库操作中的若干单元的管理,事务管理的目标是完整性,一次中的若干操作要么都执行成功,要么都失败。

事务特性

ACID(原子性(Atomicity,或称不可 分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久 性(Durability))

原子性:一个事务的一组操作(一个或多个sql语句),要么都执行成功,要么都不成功。

隔离性

为什么使用隔离性?

    为了保证多个事务在并发执行的过程中,互不影响。

出现问题:脏读、不可重复读、幻读

脏读​​​​​​​

事务A开启事务,查询表数据;

事务B开启事务,向表添加一条数据后,未提交;

事务A再次查询该表,查询到已经添加后的数据。

但是事务B可能会回滚,那么事务A再读到的就是脏数据。

不可重复读

事务A开启事务,查询到一条记录(例如age = 10),

事务B开启事务,修改这一条记录(age = 20),并提交事务,

事务A再次查询,事务A为修改后的数据(age = 20)。这就是不可重复读

幻读

事务A开启事务,查询到一条记录,

事务B开始开启事务,增加一条记录,提交,

事务A再次查询,查询到两条记录。

注:幻读是数量上的变化

为了出现了这些问题,我们设置了隔离级别,隔离级别一共有四个。

隔离级别

读未提交(read uncommitted)

一个事务可以读到另一个事务还没提交的数据。

描述:事务A开启事务,查询表数据,

事务B开启事务,向表添加一条数据后,未提交

事务A再次查询该表,查询到已经添加后的数据。

但是事务B可能会回滚,那么事务B读到的就是脏数据。

问题:可能会出现脏读,其中还会出现不可重复读,幻读的情况。

读已提交(read committed))

一个事务只能查询到另一个事务已经提交的数据。

描述:

事务A开启事务,向表插入一条数据,未提交

事务B开启事务,查询该表,未查询到该条记录

事务A提交数据,事务B再次查询,查询到该条记录。

目的:解决了脏读问题

问题:会出现不可重复读和幻读问题。

可重复读(repeatable read MySQL 默认隔离级别)

一个事务开始时读到了一个数据,在事务中继续执行再次读时,读到数据与第一次是一致的。

描述:

事务A开启事务,查询到一条记录,(保存在快照中)

事务B开启事务,修改这条记录,并提交。

事务A再次查询,查询到的是原来的记录。

目的:解决不可重复读问题,

注:mysql在可重复读级别上只在Innodb引擎中不存在幻读问题

可串行化(serializable)

对表进行操作时,只能是一个一个事务执行,如果有一个事务在执行中,即使是读操作,那么其他事务也必须进行等待。

持久性:事务执行完成后,将执行后的数据持久化的保存到硬盘上,不可回滚。

一致性:在事务执行之前和之后都是为了保持数据库的完整性。

事务设置

SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED --读未提交

事务实现原理

redolog 用于保证事务持久性;undolog 则是事务 原子性和隔离性实现的基础。

原子性实现:使用 undo log对事物进行回滚,记录一个相反的操作。执行一个修改操作。后来又回滚了,那么数据需要知道执行前是什么样子的。

比如:在使用insert 操作时,undo log日志就会记录一个相反的操作 delete;在执行 delete 操作时,会同时记录insert操作。这样在事务回滚时,可以借助日志信息进行还原。

隔离性

持久性实现:mysql对数据操作时,并不是立即将数据写入磁盘,这样io多,效率低。数据又不能一直保持在缓存中,万一服务器宕机,那么数据就不存在了。mysql提供了redolog日志,可以将数据先暂时保持在日志中,记录哪些数据发生了修改,定期将日志数据写到磁盘。

隔离级别实现原理(MVCC)

MVCC 多版本并发控制

目的:mvcc机制是为了提高mysql并发方法性能(读-写,写-读);

       MVCC 使得数据库读不会对数据加锁,普通的 SELECT 请求不会加锁, 提高了数据库的并发处理能力 。 借助MVCC,数据库可以实现READ COMMITTED,REPEATBLE READ等隔离级别。

       每个事务在对表记录操作时,会将之前的数据保存在undo log 中,表中有两个隐藏列(事务id,版本id)一个保存了行的事务 ID(DB_TRX_ID),一个保存了行的回滚指针(DB_ROLL_PT)。

事务1 第一次插入数据 

事务 2 第一次修改数 

 事务 3 第二次修改数据

ReadView

ReadView中存储一些当前操作的活跃事务对象id,记录当前事务id、最大或最小

当为可重复读时,事务A查询后,事务B进行2次修改后,事务A再查,只能查到当前的数据,不能读到修改后的数据。

关注点是从readView 中判断应该获取版本链中的哪条记录出来

对于看到的读已提交,为什么其他事务提交后,就可以读到最新的版本?

      因为每次读的时候就会产生一个readView ,读到最新的数据,称为当前读。

      对于可重复读,是第一次读取数据时,就会生成readView,这样之后,再次读时,与第一次的版本是一致的,称为快照。

多版本并发控制, 为了读已提交,可重复读提供版本记录,

读已提交:因为每次读的时候读到其他事务提交的最新记录

可重复读:因为读的时候会拍照,在同一个事务中一直从此快照中读

锁机制

按锁的粒度划分

行级锁:一个事务在对某行数据操作(写),其他事务不能对此行进行操作,锁定一行。

优:并发性好

缺:加锁的频率高(开销较大)

mysql中innodb支持行锁(默认为行锁),myisam不支持行锁

表级锁:一个事务在对某表中某行操作时,将某个表锁定了,其他事务不能操作。

优:并发性低

缺:加锁的频率少(开销小)

mysql中innodb和myisam都支持表锁。

间隙锁:对表中数据的某个区间进行加锁(区间锁)

update test set name = '111' where id > 1 and id < 10

排他锁(X):写锁,实际意义上的加锁,有事务进行写操作,其他事务不能执行。执行增、删、改操作时,自动加锁;查询语句如果有需要,也可以加排他锁。

select * from test where id = 5 for update

共享锁(S):读锁,添加查询语句,添加共享后,其他事务也可以添加共享锁,但是其他事务就不能添加排他锁了。

select * from test where id = 5 lock in share mode

Sql优化

为什么要对Sql进行优化?

      在数据量增大时,sql的执行效率对程序运行效率的影响逐渐增大,优化sql,可以提高查询效率。

几种优化方案

  • 适当添加索引(添加索引的原则)

  • 应尽量避免索引失效

  • 状态字段/流程(尽量使用整数类型)

  • 尽量使用varchar(定长使用char,变长使用varchar)

  • 查询结果列出需要的列,不要用 *

  • 尽量避免一次性查询过多的数据

  • 尽量避免值为null,可以赋给默认值。null是会占空间的,在count统计时,不被统计

索引失效情况

  • 组合索引中,不满足最左前缀原则

  • like 模糊查询

  • 以 null 为条件作为查询语句

  • 例:select id from test where num is null

  • 使用or进行条件连接

  • 在where 中使用表达式/函数

执行计划

EXPLAIN

sql发送给服务器,在服务器内如何执行,执行流程是怎们样的,先执行谁,有没有用到索引等.....

EXPLAIN 作用 

  • 表的读取顺序
  • 数据读取操作的操作类型
  •  哪些索引可以使用
  • 哪些索引被实际使用
  • 表之间的引用
  • 每张表有多少行被优化器查询

EXPLAIN 使用

使用explain关键字,添加到查询语句的前面,输出sql执行过程的参数。

EXPLAIN SELECT * FROM USER WHERE id = 1

1. id

sql执行顺序

例如有嵌套的子查询

主查询id 1

子查询id 2 表名子查询是先执行

2. select_type

表示查询结构

simple 简单查询

PRIMARY 主查询

SUBQUERY 子查询

3. type

查询性能指标

system>const>eq_ref>ref>range>index>ALL

system 表中只有一条记录

const 通过索引一次性可以找到

ref 使用了索引 例如姓名,查询出来可能会有多条数据

range 使用了索引 范围查询

index 类型只遍历索引树。

All 全表扫描 索引失效 查询所有数据了

主键自增 B+ 123456789 203423

4. possible_keys

可能用到的索引,key 实际用到的索引

 

原网站

版权声明
本文为[追梦的烟火]所创,转载请带上原文链接,感谢
https://blog.csdn.net/m0_61470267/article/details/125334989