Mysql笔记

0.索引结构

0.1 B+树

叶子节点:单向链表,包含了所有插入的元素
非叶子节点:主要起到索引的作用
在这里插入图片描述
mysql中,B+树的每个非叶子节点存的是索引和指针,叶子节点还是个双向链表,提高区间访问的性能,每个节点都是存放在Page(页)

1.Mysql存储引擎

1.1.InnoDB

Mysql5.5后,InnoDB是默认的存储引擎

  • 特点
    DML(增删改)操作遵循ACID模型,支持事务(原子性、隔离性、一致性、持久性)
    行级锁,提高并发访问性能
    支持外键约束,保证数据的正确性 和完整性
  • 文件
    xxx.idb

索引结构:
B+Tree,相对于一般二叉树如果按顺序插入,可能造成单链表结构,并且如果数据量大时,层级会增高,查询效率低。
相对于BTree,B+Tree中每页中不存放数据,只存放节点和指针,那么存放的指针就会变多,指针多了,相同数据量下,层级将变少,效率更高。

1.2.MyISAM

  • 特点
    不支持事务,不支持外键
    支持表级锁
    访问速度快
  • 文件
    xxx.MYD、xxx.MYI、xxx.sdi
特点InnoDBMyISAMMemory
存储限制64TB
事务安全支持--
锁机制行锁表锁表锁
B+树索引支持支持支持
hash索引--支持
全文索引支持(5.6以后)支持-
空间使用N/A
内存使用中等
批量插入速度
支持外键支持--

2.性能分析

2.1.慢查询日志

慢查询日志记录了所有执行时间超过指定参数(默认10秒)的所有SQL语句的日志
通过show variables like 'slow_query_log'命令查看是否开启慢查询日志。
在这里插入图片描述
Mysql的慢查询日志默认不开启,可以通过修改配置文件windows(my.ini),Linux(/etc/my.cnf)开启日志,

Windows下:5.6版本以后取消了参数log-slow-queries,更改为slow-query-log-file
在这里插入图片描述
开启了慢查询日志后,如果有慢查询操作,便会在日志文件下生成日志记录

# Time: 2023-02-17T14:11:04.279014Z
# User@Host: root[root] @ localhost [::1]  Id:     8
# Query_time: 2.073090  Lock_time: 0.000059 Rows_sent: 1  Rows_examined: 2000000
SET timestamp=1676643064;
SELECT COUNT(*) FROM player WHERE MONEY = 1000;

2.2.profile详情

profile能够在SQL优化时帮助我们了解时间都消耗到哪里去了
在这里插入图片描述
show profile for query [Query_ID];查具体耗时
在这里插入图片描述

2.3.explain

explain可以获取Mysql如何执行select语句的信息,包括在select语句执行过程中表如何连接和连接的顺序

  1. id字段:

    如果ID相同,则表示sql语句是从上往下执行的:tp–>t–>p。
    在这里插入图片描述
    如果ID不同,则ID越大的越先执行。t–>m–>subquery2–>p
    在这里插入图片描述

  2. select_type:
    表示select的类型,常见simple,primary等

  3. type:
    表示连接类型,性能由高及低依次为NULL、system、const、eq_ref、ref、range、index、all
    const:主键或唯一性索引、ref:普通索引、index:用了索引,但遍历整个索引树、all:全表扫描

  4. possible_keys:
    显示可能在这张表上的索引,一个或多个

  5. key:
    实际用到的索引,如果没有则是NULL

  6. key_len:
    使用到的索引的字节数

  7. rows:
    查询行数(预估值)

  8. filtered:
    返回结果行数占需读取行数的百分比,值越大越好。

2.4.索引使用规则

  • 最左前缀法则
    select语句中使用联合索引查询时,会从联合索引的最左侧开始匹配,并且不跳过中间的列,如果where后面没有联合索引中的部分字段,那么索引将部分失效。
  • 索引列运算
    不要在索引上进行运算,索引不要使用运算函数,字符串索引要加引号,否则索引将失效。
  • 模糊查询
    如果是头部模糊匹配'%name',则锁引失效
  • OR连接
    用or关键字时,只要or任意一侧的索引失效,那么另一侧的索引也将失效
  • 数据分布
    数据库判断走全表扫描可能会比匹配索引快时,索引也会失效

2.5.sql优化

2.5.1.插入优化

  • 批量插入
    批量插入最好用一条insert语句执行完所有数据的插入,如果数据量大于1000条,再分为多条insert语句插入,或者使用存储过程循环插入
  • 手动提交事务
    执行多条insert语句时,开启事务,最后统一提交事务
  • 主键顺序插入
    数据插入时,尽量按主键顺序插入,如果是乱序插入,会出现索引页分裂现象
  • 大批量插入数据
    如果一次性需要插入大批量数据,可以使用Mysql数据库提供的load指令进行插入

2.5.2.主键优化

数据插入时,尽量按主键顺序插入,如果是乱序插入,会出现索引页分裂现象
在满足业务需求的情况下,尽量降低主键的长度
尽量不要使用UUID做主键或者是其他自然主键
业务操作时,避免对主键进行修改

2.5.3.order by 优化

  1. using filesort:读取满足条件的数据后,在排序缓冲区sort buffer中完成排序操作,所有不是通过索引直接返回排序结果的都叫filesort排序
  2. using index:通过有序索引顺序扫描直接返回有序数据,不需要额外排序,效率更高。默认索引都是升序索引ASC
    多字段排序时,也遵循最左前缀法则。
    尽量使用覆盖索引

2.5.4.group by 优化

在分组查询时,通过索引可以提高效率。
索引也需要满足最左前缀法则。

2.5.5.limit优化

一般分页查询时,通过创建覆盖索引能够比较好的提高性能,可以通过覆盖索引加子查询形式进行优化

2.5.6.count优化

效率排序:count(字段)<count(主键id)<count(1)=count(*)

2.5.7.update优化

update时,where后面没有用到索引,这时加的锁是表锁

3.锁

3.1.全局锁

全局锁就是堆整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的DDL语句,DML语句,以及更新操作的事务提交语句都将被阻塞。
通过FLUSH TABLES WITH READ lock;命令对数据库加锁,UNLOCK TABLES命令解锁。

3.2.表级锁

每次操作锁住整张表,锁定粒度大。发生锁冲突的概率最高,并发度最低。MyISAM 、InnoDB 、BDB存储引擎都支持表级锁

  • 表锁

    • 读锁(read lock):
      语法:加锁lock tables 表名 read;加了读锁后,客户端就只能进行读操作,而阻塞改操作。释放锁unlock tables
    • 写锁(write lock):
      语法:lock tables 表名 write;客户端加了写锁后,对自己客户端的读和写都不受影响,但其他客户端会阻塞读和写。释放锁unlock tables
  • 元数据锁(mete data lock, MDL)
    MDL加锁过程是系统自动控制的,无需显式使用,在访问一张表的时候会自动加上。MDL锁主要保护表元数据的数据(表结构)一致性,在表上有活动事务的时候,不可以对元数据进行写入操作。为了避免DML与DDL冲突,保证读写的正确性
    查看元数据锁:SELECT object_type,object_schema,object_name,lock_type,lock_duration FROM performance_schema.metadata_locks;

  • 意向锁
    为避免行锁和表锁冲突,当事务A申请行锁时,数据库会自动先开始申请表的意向锁,再申请行锁,这样B事务想要申请表锁时就只需判断是否存在意向锁,如果存在,则进入阻塞,直到A事务释放了锁

3.3.行级锁

每次操作所住对应的数据行,锁定的粒度最小,发生锁冲突的概率最低,并发度最高。只有InnoDB支持行级锁。
InnoDB的数据是基于索引组织的,行级锁是对索引进行加锁来实现的。

  • 行锁(Record Lock):锁定单行记录,阻止其他事务的update和delete。
  • 间隙锁(Gap Lock):锁定索引记录的间隙,确保索引的间隙不会发生改变,防止其他事务在这个间隙进行insert,产生幻读
  • 临键锁(Next-Key Lock):行锁和间隙锁的组合,会同时锁住行记录和索引的间隙。

3.3.1.行锁(Record Lock)

InnoDB的行锁是针对索引加的锁,并且该索引不能失效,否则会升级为表锁
两种类型的行锁:共享锁(S)排他锁(X)

  1. 共享锁:允许事务读一行,阻止其他事务获得相同数据,共享锁之间是兼容的,但共享锁和互斥锁之间是互斥的
  2. 排他锁:允许获取排他锁的事务更新数据,阻止其他事务获得相同数据的共享锁和排他锁
sql行锁类型说明
INSERT排他锁自动加锁
UPDATE排他锁自动加锁
DELETE排他锁自动加锁
SELECT不加任何锁
SELECT … LOCK IN SHARE MODE共享锁
SELECT … FOR UPDATE排他锁

默认情况下,InnoDB在RR事务隔离级别运行,InnoDB使用next-key锁进行搜索和索引扫描,以防止幻读。
行锁是针对索引加的锁,如果不通过索引条件检索数据,那么InnoDB将对整个表进行加锁,升级为表锁

3.3.2.间隙锁/临键锁

索引上的等值查询(唯一索引),给不存在的记录加锁时,优化为间隙锁。
索引上的等值查询(普通索引),向右遍历时最后一个值不满足查询需求时,Next-Key Lock退化为间隙锁
索引上的范围查询(唯一索引)会访问到不满足条件的第一个值为止

4.InnoDB引擎

4.1.逻辑存储结构

TableSpace(表空间):一个mysql实例可以对应多个表空间,用于存储记录,索引等数据,即ibd文件
Segment(段):InnoDB是索引组织表,数据段就是B+树的叶子节点,索引段即为B+树的非叶子节点。段用来管理多个区
Extent(区):表空间的单元结构,每个区的大小为1M,默认情况下,InnoDB一个页为16K,一个区有64个页
Page(页):磁盘管理的最小单元,每页大小默认16K
Row(行):包含Trx_id、Roll_pointer。
在一般情况下,InnoDB一次最少从磁盘中读取一页的内容到内存中,一次最少把内存中的一页内容刷新到磁盘中。

4.2.架构

4.2.1.内存结构

在这里插入图片描述

  • Buffer Pool:缓冲池是主内存中的一个区域,当进行CURD操作时,会先操作缓冲池中的数据,并以一定的频率刷新到磁盘中。以Page页为单位,分别为
    free page:空闲页;clean page:被使用过,但未修改;dirty page:修改过,但未刷新到磁盘中
  • Change Buffer:更改缓冲区(针对非唯一二级索引页),DML语句执行时,如果Buffer Pool中没有,不会直接操作磁盘,而是读到Change Buffer,再以一定频率刷新到Buffer Pool,再一起刷新到磁盘中
  • Adaptive Hash
    Index:自适应Hash索引,InnoDB会自动判断,当Hash值比B+树更适合做索引时,会自动建立Hash索引。
  • Log Buffer:日志缓冲区(日志都有缓冲区),为了提高效率,将log日志数据(redo log、undo log)定期刷新到磁盘空间中。

4.2.2.磁盘结构

在这里插入图片描述

4.2.3.后台线程

后台线程的作用是将内存空间的数据刷新到磁盘空间

4.3.事务原理

事务是一组不可分割工作单位,这组操作要么同时成功,要么同时失败。

4.3.1.四大特性:ACID

原子性:事务是一组不可分割工作单位,这组操作要么同时成功,要么同时失败。
一致性:事务完成时,必须使所有的数据都保持一致状态。
隔离性:保证事务不受外部并发操作影响的独立环境下运行。
持久性:事务一旦提交或回滚,数据库中的数据的改变将时永久的。

4.3.2.事务隔离级别

事务并发时出现的问题:

  • 脏读:事务T1读取了事务T2修改但未提交的数据之后,事务T2回滚,T1读取的数据就是无效的
  • 不可重复度:事务T1多次读取一份数据,同时事务T2修改了这份份数据然后提交了,这时T1读取数据将不一致。
  • 幻读:一个事务T1按照条件查询数据时,没有对应的数据行,这时事务T2插入了这条数据,于是T1在插入数据时,又发现这行数据已经存在,但再次查询,却还是查不到数据。

mysql中的四种事务隔离级别如下:

隔离级别脏读不可重复读幻读
read uncommitted
read committed×
repeatable read××
serializable×××

查看当前的事务隔离级别通过tx_isolation变量或者transaction_isolation(版本8.0以上使用);
select @@TRANSACTION_ISOLATION

#设置事务的隔离级别:
set session| global  transaction isolation level read uncommitted;

4.3.3.redo log

保证事务的持久性。
重做日志,记录事务提交时,如果数据发生变化,会记录修改信息到redo log buffer中,直接刷新到磁盘中,如果后台线程在将缓冲区里的数据刷新到磁盘中时发生错误,将会通过redo log中的日志进行数据修复。从而保证事务的持久性在这里插入图片描述
redo log是循环写的,并不会持久保留下来

4.3.4.undo log

回滚日志,用于记录数据被修改前的信息,undo log是逻辑日志,redo log是物理日志。
当执行rollback时,从读取undo log中的信息,进行回滚。用于保证事务原子性

4.3.5.MVCC

  • 当前读
    select lock in share mode (共享锁), select for update; update; insert; delete (排他锁)这些操作都是一种当前读,读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。
  • 快照读
    简单的select(不加锁)就是快照读,读取的是记录数据的可见版本,即不加锁的非阻塞读
    read committed:每次select都生成一个快照读
    repeatable read:开启事务后,第一个select语句才是快照读的地方
    serializable:快照读会退化为当前读
  • MVCC
    即多版本并发控制(Multi-Version Concurrency Control)。主要是为了提高数据库并发性能,用更好的方式去处理读-写冲突,做到即使有读写冲突时,也能做到不加锁,非阻塞并发读

隐式字段

  • DB_TRX_ID:最近修改事务ID,记录插入这条记录或最后一次修改该记录的事务ID
  • DB_ROLL_PTR:回滚指针,记录上一个版本,用于配合undo log,指向上一个版本
  • DB_ROW_ID:隐藏主键,如果表结构没有指定主键,生成该字段作为隐藏主键。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值