• MySQL高级(二)


    目录

    索引

    索引优劣

    索引分类

    聚簇索引和非聚簇索引

    事务

    事务特性

    隔离级别

    事务实现原理

    隔离级别实现原理(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 表名;

    例:

    1. select * from table where a=’’and b=’’ 索引生效
    2. select * from table where b=’’and a=’’ 索引生效
    3. select * from table where a=’’and c=’’ 索引生效
    4. 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 实际用到的索引

     

  • 相关阅读:
    动态库.lib与.dll关系、visual studio工程库路径配置浅析
    JS--数组类型 Array 1
    连锁药店的自有品牌之争:老百姓大药房能否突围?
    一文教你理解Kafka offset
    DLL动态链接库的导入导出
    ZKP3.2 Programming ZKPs (Arkworks & Zokrates)
    银河麒麟V10安装MySQL8.0.28并实现远程访问
    医学影像 DICOM转NIFTI(.dcm 到 .nii)
    Postgresql中ParamListInfoData的作用
    Rowset Class
  • 原文地址:https://blog.csdn.net/m0_61470267/article/details/125334989