in和exists的区别?
in是内外表hash连接,exists是对外表做loop循环,每次loop后再对内表查询,如果外表小就用exists;
not in和not exists前者是全表扫描,后者是可以走索引
锁
对于标准的插入操作,InnoDB 实际上使用了一种称为"插入意向锁"的轻量级锁定机制。在插入一条记录时,InnoDB 会对插入的行加上排他锁(X Lock)。但是,这种排他锁是针对新插入的行的,它防止其他事务修改或删除这个新行。在日常操作中,你可能不会直接"看到"插入操作加的锁,特别是如果事务很快就提交了。除非使用专门的工具(如 SHOW ENGINE INNODB STATUS
或性能模式中的表)在恰当的时间检查,否则插入操作引起的锁可能对用户来说是不可见的。
怎么存储emoji?
utf8不行,是阉割版的,需要用utf8mb4
drop、truncate、delete的区别?
前两者是DDL语句,不可回滚,后者是DML语句
删除整张表、删除所有数据保留表结构、删除符合条件的行
UNION和UNIONALL的区别?
前者会去重、后者不会、后者更快,union有临时表,所以条件尽量放在union子查询里面,不然索引失效
count(1),count(*).count(name)的区别?
count(1)和count(*)性能上没有区别,仅仅就是简单统计行数,用1代表代码行,列多就比count(*)快
count(*)就是全表扫描统计所有行数据,除非使用索引优化查询,但是在MyiSAM中是维护了一个计数器的。一个字段就快
count(name)会忽略为null,有主键就快
执行顺序?
数据库架构?
客户端、server层、存储引擎层
连接池:将连接缓存下来,下次使用,以提高服务器性能
管理工具和服务:备份恢复、Mysql赋值、集群等等。
SQL接口:接受命令返回结果。
解析器:将SQL拆分成数据结构,进行验证和解析
优化器:SQL优化
缓存器:查询缓存
文件系统:
存储引擎
执行顺序?
查看权限、查缓存、解析器、优化器、调用引擎接口,执行返回结果,缓存带来的问题比解决的多。
存储引擎?
选择,大多数情况下选择InnoDB,一些特性innodb没有还无可替代,但是临时存放数据、数据量小,且不需要安全性可以选择MEMORY(hash索引),主要是用来插入和查询记录,则就用MYISAM,地理空间的搜索
区别是什么?
事务支持,锁的粒度、索引类型(MYISAM是B树,允许没有索引和主键)、myisam有变量保留了行数。外键支持。myisam存储成三个文件
日志?
error log:对启动运行关闭进行了记录,定位问题
慢查询日志:记录超过设定时间的查询日志,方便进行优化,也可以设置没用索引的
二进制日志:用于备份恢复。记录了所有的DDL和DML语句,当然是已经提交的,除了select show;
undo log回滚日志:每一行记录了事务id和下一条的指针。保证事务id自增
redo log:记录了未刷进磁盘的已提交的日志,当然写一条就会有,但是有标志位显示提交没提交,只用在恢复数据
redo log:
,默认48M一个
为什么两个?轮流替换写
作用:
一种物理日志
用在数据库崩溃后的自己恢复,redolog存在2PC,当commit的时候redolog pool会同步落地到磁盘中,当然binlog也会写,但是binlog无法区分哪些从bufferpool刷进去了,哪些没有。
事务在访问真正的数据的时候,都要将页面缓存到buffer pool中,那如果还没刷进磁盘就断电了,如何保证持久性。同时刷新一个完整的数据页太浪费了,随机IO也比较慢,就诞生了redo log日志,一条redo log日志格式主要有type、表空间id,页号,偏移量,然后具体的内容,就快一些。所以既保证了持久性,也能避免资源浪费。顺序写入,有简单,有复杂,比如插入可能要更新MAX_ROW_ID,插入主键索引,二级,联合很复杂
mysql性能瓶颈主要是因为redolog!!!!
同时redo log自己也是有缓冲区的,事务提交时必须将这些对应的日志刷进磁盘。0事务提交时交给后台线程去做,1提交时同步刷新默认值,2刷到缓冲区。或者是占比超过一半刷,又或者是每秒刷,再或者是正常关闭的时候刷。
有prepare(binlog写入之前)和commit(binlog写入之后)状态,两阶段提交就是为了让这两个状态保持逻辑一致。
binlog和redolog区别?
首先:binlog是用于数据库崩溃后的人工恢复,而redolog是人不可见的,主要是数据库自己用。
第二:binlog是二进制文件,逻辑日志,是所有数据库共用的,而redolog是innodb自己用的两个区域,有自己的格式type、表号、页号、偏移量、数据物理日志
第三:binlog追加,redolog循环写
第四:binlog记录所有的DDL和DML除了select和show,redolog是事务里的
第五:提交了的都在binlog,binlog根本不知道哪些刷盘了,哪些没有
mysql永不宕机就可以不要这个东西,影响性能
undo log日志:
insert一条
delete会在原本的记录头上将标志位修改为1,这里是为了事务隔离级别考虑,事务提交后有专门的线程来删除。
update两种情况不更新主键的话可以就地更新再修改,也可以删除后插入,主要是考虑页占的空间,后面一种设计了一种类型为TRX_UNDO_UPD_EXIST_REC的undo日志。如果更新了主键因为要迁移就只能删除后更新了,此时一条插入一条删除。
索引type:
system:只有一套记录,且准确
const:根据主键或者唯一二级索引等值匹配
eq_ref: 连接查询被驱动表通过主键或者唯一二级索引等值匹配
ref:普通二级索引匹配
index:索引
range:大于小于这种
ALL:全表
InnoDB执行引擎:
双写、自适应hash、buffer pool
双写缓冲区:
范式化设计和反范式化设计:
1、原子性不可再分
2、实体主键完全依赖于关键字
3、不包含其他表中已包含的非关键字信息
优势:越精简、越标准、无冗余
如何选择?
反范式化将一些简单的数据进行冗余;汇总,比如用户有一些消息的发送次数,用户点击次数(高并发下的)多个槽进行分散(避免互斥锁,热点分散、并发度增加)
字段优化:
更小更好(更少的磁盘、内存、CPU高速缓存、CPU处理周期更少),如果能选择整形就不选字符串,因为字符串还有字符集以及校对规则!
简单就好、避免null值(索引和索引统计更加的复杂,同时在行数据里面也要额外记录,对于性能提升不大)
JAVA中要做封装类型,不然不能为null。
整数int:tiny、small、medium、int、big==long,无符号存储上升一倍 int(数量)是跟显示有关。
实数:float、double、decimal(CPU不支持,通过字符串存储的),数据量很大,精度保证、效率保证,存储bigint,数据进行放大!!!
字符串类型:char(定长、更省、磁盘分配固定大小内存、排序操作等)、varchar(最大长度比平均长度常很多)、blob(二进制、关联、单独一张表)、text(字符集、关联、单独一张表)、enum、set
日期:datatime、timestamp只到s,更小粒度bigint
B+树与B树?
B*树(Oracel),非叶子节点也用链表连起来了
优势:B树非叶子存放数据、存储的更少,B+树范围查找更好,同时都要查到叶子节点更加稳定、扇出更大
索引?
B+树索引:
- 聚集索引、聚簇索引,主键查询可以拿出所有行数据,没有主键也有row_id
- 二级索引:存字段数据,下面+主键的id,回表,覆盖索引(最左前缀)
自适应Hash索引:
- Innodb三个之一,一般等值查询,热点数据监控,O(1),拉链法解决冲突,内部操作,干预不了
全文索引:
- 基本没用
高效创建策略:
- 一般最多用一个二级索引,但是也有索引合并,索引取交集。
- 主键列索引类型尽可能小。
- 索引离散型尽可能地高!不然数据很多,宽度很高,没有区分度
- 前缀索引:不能分组、不能排序,索引更小
- 后缀索引:不支持,前缀反过来
- 只为搜索、分组、排序创建索引
- 联合索引:优先将选择性最高的,按照运行顺序调整次序
- 三星索引:数据在一起,数据顺序与查询顺序一致,查出来的列包含所需要的所有
调优:
架构调优(读写分离、分库分表)、MYSQL调优、硬件和OS调优,主要做索引调优!
查询优化:
慢查询,核心原因:数据太多了
- 查询了不需要的数据呢?比如limit 10000,20的情况。
- 查出全部的列?select * 这种,如果表变化了,就会产生错误,同时回表,全表扫描。
- 重复查询相同的数据?reids
- 究竟是服务时间还是排队时间?
SQL查询:
- 使用覆盖索引
- 重写复杂的SQL,多表那些
- 没有用到索引也可以打开记录在慢查询里面
- mysqldumpslow命令:mysqldumpslow -s(c,t,l,r) solw.log;筛选
执行计划:
EXPLAIN
select_type:
type:
System>const(主键等值查询)>eq_ref(连接中等值匹配相关索引)>ref(二级索引等值匹配)>ref_or_null>index_merge>range>index>ALL
key_len:
utf-8字符三个字节,同时记录长度和null一个字节
索引优化:
- 不在条件上做加减、函数操作。mysql8有函数索引,走的type=index
- 全值匹配:和联合索引有关系,联合索引里面的都加进去
- 最左前缀原则:b+树的特性
- 范围条件放在最后:中间有范围会导致后面的列全部失效,无法充分利用
- 尽量不用*,查覆盖索引里面的
- is null is not null
- like
- or 前后条件
- 字符串加引号
- !=要慎用
- 每一个null都是不一样的
- 优化子查询,子查询是嵌套查询,嵌套查询会创建临时表,创建和销毁都会占用系统资源以及花费一定的时间
- 小表驱动大表
- union是创建临时表,无法利用索引,将where等写到union子查询中
- 索引下推优化:分为客户端、server层、存储引擎,如果没有索引下推,则通过存储引擎层检索数据之后,server过滤,下推就是将条件也给存储引擎,条件符合才返回,减少了回表的次数。
事务:
ACID 原子(undolog) 一致 隔离(锁、Mvcc) 持久(redolog,已经提交的事务永久生效)
隔离级别:读未提交、读已提交、可重复读、串行化
保存点 savepoint
显式:begin start transaction
隐式:update insert
隐式提交:DDL、第二个begin、slave
锁:
InnoDB提供了一个称之为innodb_autoinc_lock_mode的系统变量来控制到底使用上述两种方式中的哪种来为AUTO_INCREMENT修饰的列进行赋值,当innodb_autoinc_lock_mode值为0时,一律采用AUTO-INC锁;当innodb_autoinc_lock_mode值为1时,一律采用轻量级锁;当innodb_autoinc_lock_mode值为2时,两种方式混着来(也就是在插入记录数量确定时采用轻量级锁,不确定时使用AUTO-INC锁
- AUTO-INC锁是表级别的,当执行插入语句的时候,其它事务的插入语句都要被阻塞。
- 轻量级锁,在插入的时候获取一下AUTO-INCREMENT,然后插入
- 前者不确定多少条,后者确定多少条
执行原理:
单表:
intersection合并:and先从二级索引得到ids,再去查,减少随机io
union合并:or
sort-union合并:主键排序,
联合索引替代
多表:
连接查询:
- 本质:所有记录取出来进行匹配返回
- 优化:加条件、被驱动表条件字段加索引
Hash连接:为较小的表创建hash表,key为索引,然后通过hash表快速定位信息,适合差别较大。
Innodb引擎:
将数据分成页16KB。
行格式
数据溢出:
前两个:一个页放不下,行格式需要优化处理,只记录768个字节,然后划出20个字节指向其他页
后两个:不放具体数据,只放地址
表空间:
.ibd文件
- 表 2^32个页,难以管理
- 段(组(256个区)),逻辑分区,一个b+树两个段,一个叶子节点的段,一个非叶子结点的段
- 区(64个连续页),消除随机IO
系统表空间:
额外的信息 extend1和extend2两个区组成双写缓冲区(8以后独立了)
MySQL 8.0 对于双写缓冲区(Doublewrite Buffer)进行了重要的改进,以提高性能和可靠性。双写缓冲区是 InnoDB 存储引擎用来防止部分页面写入导致的数据页损坏的一项功能。在 MySQL 8.0 之前,双写缓冲区的实现存在一些效率问题,主要是因为它将数据写入两次(一次到双写缓冲区,一次到最终位置),这可能成为 I/O 性能的瓶颈。
双写缓冲区:顺序写,防止数据丢失,比如插入1000条,哪些插入了,哪些没写入,先写到双写缓冲区,然后写真正的文件。站在操作系统,16KB无法保证原子性。为什么又redolog还要引入双写缓冲区,redolog针对页面的偏移量操作,部分写入,不会去校验页面的合法性,如果页面部分写入,那么就会导致页损坏,因为偏移量可能发生了变化!!!!,光靠redolog恢复不了。
有一个很关键的点叫checkpoint,它会保证redolog满之前将脏页进行刷新,刷新成功后,才会将redolog日志中的部分数据标记为无效。
buffer pool 128M
为了方便处理增加了控制块,表空间,页号之类的
free链表:空闲的控制块,要访问数据页时候,首先是缓存到缓存中,如何判断呢,通过表空间号和页号hash区分
flush链表:脏页面,不一致先加到flush链表进行批量提交
缓存淘汰机制:
LRU链表管理,实际开发中有问题:
一次读一个花销很大,所以产生了预读(线性【一个区超过56个页,就把下一个区的全部加进去】)
随机预读:在一个区里访问了13个页面,就把本区全部加载
如果是全表扫描,一次就刷新一次了。出现了划分区域的LRU链表,no-young 37%,young 63%,和JVM垃圾回收相反,先进old,然后一定时间后才访问的避免了全表扫描的频繁使用,认为是缓存数据,就加入young区。
MySQL 8.0 的双写缓冲区改进
-
分离的双写缓冲区 :MySQL 8.0 引入了一个重构的双写缓冲区架构。在以前的版本中,双写缓冲区是在系统表空间(
ibdata1
文件)中管理的,这意味着所有的 I/O 操作都集中在一个地方,可能会导致磁盘 I/O 瓶颈。MySQL 8.0 允许双写缓冲区被分离到其自己的文件中,这有助于分散 I/O 压力,提高并发写入性能。 -
更优的写入模式:MySQL 8.0 对双写操作进行了优化,减少了与双写缓冲区相关的 I/O 开销。新的实现更有效率地管理磁盘写入,特别是在高并发环境下。
-
可配置的双写缓冲区:在 MySQL 8.0 中,双写缓冲区的行为变得更加可配置。管理员可以根据具体的工作负载和性能需求调整双写缓冲区的大小和行为,以获得最佳的性能平衡。
-
改进的恢复速度:双写缓冲区的优化还意味着在数据库崩溃后的恢复过程更加高效。因为双写缓冲区的管理更加高效,所以在系统启动时处理双写缓冲区的数据可以更快完成,从而减少了数据库恢复时间。
快速加列:
一条update语句的执行顺序
死锁
发生死锁后者会加锁失败,然后查看日志,模拟现场