MYSQL 复苏2

关于B树B+树问题纠正:

B树和B+树是允许键值重复的。虽然大部分的教程基于不支持重复,有的甚至直接说不支持重复真的请不要误导。 B+树中遇到重复键值的方法主要是采用溢出页的方法。即分配一个溢出页来存放所有重复键值以及其记录的偏移量:这也能很好的解决下面的辅助索引关于索引值重复的问题

在这里插入图片描述

InnoDB中的索引:

  • 聚集索引/ 聚簇索引:只建立一颗B+树 (索引树为主键)

    将表的主键用来构造一棵B+树,并将整张表的行记录放在B+树的叶子节点中。对于聚集索引来说,叶子节点会放置这个所有的数据,而且根据主键式排好序的。同时叶子节点间本身就是双向链表的数据结构,我们通过主键去索引相似值的时候是很快的

    即使一张表没有创建主键,Mysql也会隐式地创建一个rootid (隐含主键)。

  • 辅助索引/ 二级索引: 建立两颗B+树 (查询字段 + 聚簇索引)

    在聚集索引的基础上,如果我们筛选的对象字段并不是主键,难道我们就要遍历整个表了么?InnoDB也支持为这些非主键字段建立索引,我们称之为辅助索引或者说二级索引。

    辅助索引的叶子节点不会放整行数据,只会放置当前字段的信息与主键信息方便提取数据 。在查找数据是,先提取主键,再通过主键到聚簇索引查询到这个行数据。这种查找方法叫做回表

  • 联合索引/ 复合索引:建立两颗颗B+树 (一颗B+树索引值按优先级进行排序), 索引值的结果还是id + 聚簇索引。将表上多个列组起来进行索引,也可以用覆盖索引不进行回表

  • 自适应Hash索引: innoDB存储引擎内部监控索引热数据然乎内部船舰hash索引。称之为自适应Hash索引(Adaptivr Hash Index, AHI), 控制参数innode_adaptive_hash_index 与innode_adaptive_hash_indexs_parts (调整我们Hash表的个数,默认8)

    show engine innodb status;
    INSERT BUFFER AND ADAPTIVE HASH INDEX
    -------------------------------------
    Ibuf: size 1, free list len 0, seg size 2, 0 merges
    merged operations:
     insert 0, delete mark 0, delete 0
    discarded operations:
     insert 0, delete mark 0, delete 0
    Hash table size 2267, node heap has 0 buffer(s)
    Hash table size 2267, node heap has 0 buffer(s)
    Hash table size 2267, node heap has 0 buffer(s)
    Hash table size 2267, node heap has 0 buffer(s)
    Hash table size 2267, node heap has 0 buffer(s)
    Hash table size 2267, node heap has 0 buffer(s)
    Hash table size 2267, node heap has 0 buffer(s)
    Hash table size 2267, node heap has 0 buffer(s)
    0.00 hash searches/s, 0.00 non-hash searches/s
    

    Tips: 热数据。指经常使用的IO频繁的数据。这类数据会被存储在缓存中方便快速调用。

  • 全文检索之倒排索引:事先将相关内容关键字并保存索引值。用于数据库中类似正则的字段搜索(这玩应就是耍流氓,咋优化也是白搭)。倒排提取有一定的规则,通过Terms 词向搞出来的

重点:索引在查询中的使用

  1. 一个索引就是一个B+树, 索引让我们的查询可以快速定位和扫描到我们需要的数据记录上,加快查询速度
  2. 一个 select 查询语句在执行过程中一般最多能使用一个二级索引, 即使在where语句中使用了多个二级索引

扫描区间: 由于叶子节点本身就是一个双向链表,我们B+ 树的作用其实就是减少我们扫描的区间,让我们不是全表扫描,性能答复上升。通过B+树找到的位置就是扫描区间。扫描区间包括单点扫描区间(a = * )和符合扫描区间(a > * and a < *). 所以上面查询的第二点就相当于每个select只能给出一个二级索引的扫描区间。另外的条件会在确定扫描空间后遍历查看是否符合

关于运算符Like, 只有匹配完整的字符串或完整字符串前缀才产生合适的扫描区间。eg. b% 可以缩小扫描区间, %b必须经过全表

复杂搜索条件下范围匹配的区间, (mysql 如何优化):

  1. mysql在多个扫描字段的时候回去判断哪个字段的扫描范围最小。对最小的扫描区间构建B+树或者说辅助索引。
  2. Mysql计算索引的代价方法:https://blog.csdn.net/why444216978/article/details/104986241 Cost = CPU Cost + IO Cost. 页是磁盘和内存之间交互等基本单位,读取一个页花费的成本默认是1.0,读取及检测一条记录是否符合搜索条件的成本默认是0.2。

索引的代价: 空间代价(B+树的空间代价) 与时间代价(B+树本身的时间复杂度是 log n, 最坏情况是 logn **2 一直分裂到顶端)

高性能索引创建策略:

  • 索引列的类型尽量越小越好,在查询时进行的比较操作越快
  • 数据类型越小,索引占用的存储空间就越少,就会花掉更少的数据页加快读写效率
  • 索引的离散型尽量高一些,这样扫描区间会减少很多

前缀索引:索引字符串时,之索引前半部分的字符串做索引,即前缀索引。后缀索引就是反过来从后面找啦。

三星索引:

索引将相关记录放到一起则一星, 索引中数据顺序核查找中的排列顺序一致则而行, 索引列中包含索引查询需要的全部列获得三星。

慢查询:慢查询日志, 就是查询慢的日志。指mysql 记录所有执行超过long_query_time参数设定的时间阈值的SQL语句的日志。该日志能为SQL语句的优化带来很好的帮助。默认情况下慢查询日志是关闭的。要使用慢查询日志功能就要开启慢查询日志功能。

什么时候用到慢查询优化:

  • 是否存在扫描额外的记录:1.查询了不需要的记录, 2. 总是去除重复列 3. 重复查询相同的数据
  • 是否扫描额外的记录: 1. 响应时间 2. 扫描的行数与返回的行数 3.扫描的行数与访问类型

怎么优化:

  1. 一个复杂查询还是多个简单查询
  2. 切分查询
  3. 分解关联查询:
    • 让缓存效率更高
    • 减少锁的竞争
    • 更容易做到高性能与可扩展
    • 较少冗余记录的查询
    • 相当于Hash关联

开启慢查询日志,可以让MySQL记录下查询超过指定时间的语句,通过定位分析性能的瓶颈,才能更好的优化数据库系统的性能。

# 慢查询日志开启方法  /etc/my.cnf
# 查询状态: show variables like 'slow_query_log'
slow_query_log=1
# 将查询时间两秒以上的sql语句记录下来
long_query_time=2

关于索引的语法:

create [UNIQUE|FULLTEXT] INDEX index_name on (filed1,field2...)
SHOW INDEX FROM table_name;
Drop INDEX index_name ON table_name

最左前缀法则:查询从索引的最左列开始,并且不跳过索引中的列。如果跳跃索引列,索引将会部分失效(跳跃后面的部分)失效。而且使用> <范围查询,范围查询后面的列索引会是失效.解决办法: 加上 =

索引失效原因:

  1. 对索引字段进行运算
  2. 字符类型不加引号
  3. 模糊查询尾匹配索引失效(可以倒转过来头匹配,极端条件下可以用全文索引)
  4. 用or 分开的条件,or的两个条件必须都是用索引否则索引失效
  5. Mysql自行计算判断,见上面计算代价方法

SQL提示,人为的告诉Mysql应该用哪个索引

explain select * from table use index(索引名称) ....
。。。。。。。。。。。。。。。 ignore index() .....
。。。。。。。。。。。。。。。 force inex() ......

视图:简单来说就是Mysql的函数,可重用,数据段结构自由,还能在一定程度上限定权限,进行迁移等等,同时不改变表原来的结构,也不会重新存储数据。属于是比较舒服的重用工具。

视图的存储过程:

CREATE PROCEDURE 存储过程名称([参数列表])
BEGIN
		--SQL语句
END;

# 调用
CALL 名称 ([参数]);
# 查看
SHOW CREATE PROCEDURE 存储过程名称
# 删除
DROP PROCEDURE [IF EXISTS] 存储过程名称

触发器:表有关的数据库对象,指在insert/ update/ delete之前或之后除法触发器定义的SQL语句合计。可用于数据完整性,日志记录,数据校验等操作。(有点像信号或者说钩子)

MYSQL 锁, 事务:

Mysql中的锁:

全局锁:锁住整个数据库实例, 数据库只读,主要用于备份4

flush tables with read lock
unlock tables

表级锁:锁住整张表。并发度较低。分为三类: 表锁, 元数据所, 意向锁

  • 表锁:读锁与写锁(读锁都共享,写锁读写都不共享—)
  • 元数据锁: 无需显示使用,访问一张表会自动加上。主要是维护表元数据的数据一致性,在表上进行DDL的时候不可以DML
  • 意向锁: 防止行锁与表锁的冲突,加表锁的时候不用对行检测是否加行级锁。意向锁又分意向共享锁: 与表读锁兼容; 一项排他锁:与表锁完全排斥。

行级锁: 锁住索引或行数据。锁定粒度最小。在InnoDB中行锁即为索引锁。

  • 行锁: 锁住相应的索引值。 包括共享锁(兼容共享锁),排他锁(都不兼容)。如果不通过索引就会升级成表锁
  • 间隙锁: 锁住索引的间隙
  • 临建锁:行锁 + 间隙锁

InnoDB引擎架构,事务原理, MVCC:

先来看Innodb的结构:

在这里插入图片描述

表空间: 以ibd文件存在于磁盘当中

段: 分为数据段, 索引段, 回滚段。 InnpDB是索引组织表, 数据段就是B+树的叶子节点, 索引段是B+树的非叶子节点。段用来管理多个Extent(区)

区是存放页的抽象结构。一个区默认为1M,存放64个数据页

页是Innodb存储引擎的最小管理单元。默认为16K

行: Trx_id 每次对记录进行改动时,都会把事务的id赋值给trx_id和隐藏列。四种Mysql的分级就是基于Trx_id实现的。可以看上面偏开头的部分。 Roll_pointer保存旧版本指针。旧版本会被写道undo.log中。配合undo.log完成row_back.

InnoDB在磁盘中的结构图如下

在这里插入图片描述

除了上述图中的结构, InnoDB还包含一个重要部分: 内存与磁盘进行数据交互的线程:

  1. Master Thread: 核心后台线程, 负责调度其他线程, 负责将缓冲池中的数据异步刷新到磁盘中,保持数据的一一致性。包括脏页的刷新, 很冰插入缓存,UNDO 页回收
  2. IO Thread: 在Innodb引擎中大量使用了AIO (异步非阻塞IO) 极大提高了数据库性能
  3. Purge Thread 主要用于回收事务已经提交了的undo_log. 在事务提奥之后前面的undo_log肯定要被更新掉/删除掉的。
  4. Page Thread 协助master thread 进行脏页处理的

InnoDB 事务原理:

  • 事务是一组操作的集合,是一个不可分割的工作单位。事务会把所有的操作作为一整个整体一起向系统系统提交操作请求。

事务的底层原理:

原子性:Undo_log, 一有问题立刻回滚肯定保证了原子性啦。Undo_log主要提供作用是回滚于MVCC. undo_log是逻辑日志(redo_log是存在缓冲区和磁盘上的物理日志) 意思就是记录当前操作相反的内容并记录好指针。出错就按照Undo_log上相反的命令运行达到回滚的效果。undo_log并不会在事务提交时销毁。因为这些日志文件虽然不能继续作用于原子性,但可以用于MVCC. undolog采用段的方式管理。

持久性: Redo_log 记录数据页的物理修改。每次修改会自动刷新。由于状态在RedO_log中保存所以完成了持久化,即即使宕机也能至少返回上一个状态。

MVCC: ( 基本概念 ):

  • 当前读: 读取的记录是最新版本,保证其他并发事务不能修改当前记录,会对读取的记录进行枷锁
  • 快照读: 不加锁,读取到的有可能是历史数据,不加锁,是非阻塞读:
    • Read Commited: 每次select 都生成一个快照
    • Repeatable Read: 开启事务的第一个select 语句才是快照读的地放
    • serializable 快照读退化为当前读( 比read Commited 多一个阻塞于加锁)

MVCC: 多版本并发控制。维护一个数据的多个版本,使读写操作没有冲突。快照读为Mysql实现MVCC提供了一个非阻塞读的过程。MVC具体的实现,依赖于数据库记录中的三个隐式字段, undo log, readView.

MVCC的实现原理:

  1. 记录中的隐藏字段:再我们创建记录的时候,innoDB会为我们隐式的额外的创建三个字段:DB_TRX_ID , DB_ROLL_PTR, DB_ROE_ID.

    隐藏字段内容
    DB_TRX_ID最近修改事务ID。 记录插入事务后最后yIC修改该记录的事务ID
    DB_ROLL_PTR回滚指针, 指向这条记录的上一个版本, 用于配合undo log回滚到上一个版本
    DB_ROW_ID隐藏主键, 如果表结构没有指定主键,将会生成隐藏字段。
  2. Undo_log日志。主要是便于数据的回滚,上文说到,undo_log不能在事务提交的时候立即删除,这里具象化删除时间:当insert的时候,产生的undo_log旨在回滚的时候需要。事务提交之后可以被立刻删除。但是当uupdate, delete的时候,产生的undo_log日志不仅回滚的时候需要,快照读的时候也需要,不能立刻删除。所以为什么不能立即删除,因为要兼顾到快照读。换句话说生成下一张快照快照的时候这些数据就可以被淘汰了。

    Undo_log版本连:在并发回滚的时候我们需要用一条链式结构保证我们回滚的准确性。

  3. readview 是快照读SQL执行MVCC提取数据的依据。记录并维护系统当前活跃的事务(未提交的) id。简单来说就是你去快照读的时候快照读本身不可能是表中的数据,那他肯定是一张视图喽。告诉你读那张快照并负责快照的删除

    所以说实现隔离级别的这篇https://blog.csdn.net/baihualindesu/article/details/100375244简直超人

所以说隔离性就是靠锁以及MVCC实现的。四种隔离级别在上面的BLOG

至于一致性, 一致性属于是原子性, 隔离性, 持久性在一起想要达到的目标。没有具体的实现手段,需要我们人为的使用令三种特性却解决和完成一致性问题。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值