关注脏页比例 select VARIABLE_VALUE into @a from global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_dirty';select VARIABLE_VALUE into @b from global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_total';select @a/@b;
这是一条建表 SQL 以及一条初始化 SQL,如果执行 select * from T where k between 3 and 5 需要执行几次树的搜索操作?
createtableT (
ID intprimary key,
k intNOT NULL DEFAULT 0,
s varchar(16) NOT NULL DEFAULT '',
index k(k))
engine=InnoDB;
insert into T values(100,1, 'aa'),(200,2,'bb'),(300,3,'cc'),(500,5,'ee'),(600,6,'ff'),(700,7,'gg');
在 k 索引树上找到 k=3 的记录,取得 ID = 300
再到 ID 索引树查到 ID=300 对应的 R3
在 k 索引树取下一个值 k=5,取得 ID=500
再回到 ID 索引树查到 ID=500 对应的 R4
在 k 索引树取下一个值 k=6,不满足条件,循环结束
在这个过程中读取了 k 索引树的 3 条数据以及回表 2 次,那么有没有可能避免回表操作?
如果执行 select ID from T where k between 3 and 5 这表明只需要查询 id 的值,而 id 的值已经在 k 索引树上了,可以直接提供结果不需要回表. 也就是说,在这个查询中,索引 k 已经覆盖了我们的查询需求,这就是 覆盖索引
最左前缀原则
联合索引的最左 N 个字段,也可以是字符串索引的最左 M 个字符
索引项是按照索引定义里面出现的字段顺序排序的,例如我们要找以张为姓的所有人可以用where name like '张%' 就可以命中索引,但如果使用'%张' 是不会命中索引的
想法:
一个脚本管理工具,类似 alias 的工具
sc add xxx
来添加需要运行的脚本,可以选择执行脚本的程序,默认是 shsc run
来运行某个脚本123123123
重点看 io uring, ebpf
#Docker
kafka docker compose 示例
#Docker
Docker 安装 MySQL
mkdir mysql-data cd mysql-data mkdir log mkdir data mkdir conf docker run --name mysql-dev --rm -e MYSQL_ROOT_PASSWORD=qwe -d mysql docker cp mysql-dev:/etc/mysql ./conf/ docker stop mysql-dev docker run -p 3306:3306 --name mysql-dev --privileged=true \ -v ./log:/var/log/mysql \ -v ./data:/var/lib/mysql \ -v ./conf/mysql:/etc/mysql \ -e MYSQL_ROOT_PASSWORD=qwe -d mysql:latest
#Docker
Docker 安装 ClickHouse
#MySQL
MySQL 优化策略
刷脏页: 脏页表示还没有写入磁盘的数据页. 什么情况下会触发?
1 和 2 会影响我们执行 SQL 的速度, 1 我们需要避免, 因为通常执行更新操作都是写 redo log
优化方案:
select VARIABLE_VALUE into @a from global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_dirty';select VARIABLE_VALUE into @b from global_status where VARIABLE_NAME = 'Innodb_buffer_pool_pages_total';select @a/@b;
innodb_flush_neighbors
来控制刷脏页时要不要一直刷临近的脏页#MySQL
事务到底是隔离还是不隔离?
假设在所有事务开始时 k = 1, 那么
为什么会这样?
1, 事务C 更新到 2 没问题
2. 事务B 的更新操作为什么会读取到 2?
- 因为更新数据都是先读后写的,读这个操作是 当前读,即读取最新值
- 如果 select 加锁也会是当前读
3. 事务A 因为可重复读所以还是 1
也可以这样解释:
如果事务C 没有在更新完第一时间提交会怎么样?
如果事务C 不提交则表明它还持有写锁, 而事务B 的 update 语句要获取读锁, 读写锁互斥, 因此被锁住了.
#MySQL
全局锁:
对整个数据库实例加读锁
Flush tables with read lock
, 使整个数据库处于只读状态, 其他更新、修改等语句会阻塞主要应用场景是全库备份, 但不推荐这样使用(除非引擎不支持事务), 备份可以用
mysql dump
使用参数-single-transcation
, 导数据之前开启一个数据, 使用视图来读取数据表锁:
lock tables ... read/write
可以用unlock tables
主动释放, 如果使用了lock tables
就只能操作指定的table
且其他线程读写 lock 的表会被阻塞MDL
, 在访问一个表的时候会自动加上. 用于保证读写的正确性#life
三亚的太阳
#MySQL
覆盖索引
这是一条建表 SQL 以及一条初始化 SQL,如果执行
select * from T where k between 3 and 5
需要执行几次树的搜索操作?在这个过程中读取了 k 索引树的 3 条数据以及回表 2 次,那么有没有可能避免回表操作?
如果执行
select ID from T where k between 3 and 5
这表明只需要查询 id 的值,而 id 的值已经在 k 索引树上了,可以直接提供结果不需要回表. 也就是说,在这个查询中,索引 k 已经覆盖了我们的查询需求,这就是 覆盖索引最左前缀原则
索引项是按照索引定义里面出现的字段顺序排序的,例如我们要找以张为姓的所有人可以用
where name like '张%'
就可以命中索引,但如果使用'%张'
是不会命中索引的索引下推
最左前缀可以用于在索引中定位记录,但如果有不符合最左前缀的部分会怎么样?
有一个需求是要查询名字第一个字是张,而且年龄是 10 岁的所有男孩”。那么,SQL 语句是这么写的:
这个语句在搜索索引树的时候,只能用 “张”,找到第一个满足条件的记录 ID3,然后索引就会失效.
在 MySQL5.6 以前时只能从 ID3 开始一个个回表, 到主键索引树上找出数据行然后对比数据
但是在 5.6 以后可以在索引遍历过程中对索引中包含的字段先做判断,直接过滤到不满足条件的记录,减少回表次数.
即以前是不会判断 age 这个字段的,但因为我们的索引是包含 age 字段的,所以现在可以利用索引下推这个功能来有优化查询速度.
#MySQL
InnoDB 的索引模型:
在 InnoDB 中,每一个索引都对应一颗 B+ 树,有下面的建表 SQL,id 与 k 都是索引列:
可以看出索引分为 主键索引 以及 非主键索引
主键索引
(聚簇索引的叶子节点存放了整行的数据,非主建索引
(二级索引)的叶子节点存放的是主键的值基于主键索引和普通索引的查询有什么区别?
select * from t where id = 1
使用主键索引则只需要查找ID
索引树select * from t where k = 6
则需要先查找k
索引树然后在到ID
索引树中在查找. 这个过程就是 回表为什么推荐使用自增主键?
B+树为了保证索引的有序性,在插入以及删除值的时候进行必要的维护.以上面这个图为例,如果插入新的行 ID 值为 700,则只需要在 R5 的记录后面插入一个新记录。如果新插入的 ID 值为 400,就相对麻烦了,需要逻辑上挪动后面的数据,空出位置。
而更糟的情况是,如果 R5 所在的数据页已经满了,根据 B+ 树的算法,这时候需要申请一个新的数据页,然后挪动部分数据过去。这个过程称为页分裂。在这种情况下,性能自然会受影响。
而使用一个递增的主键就可以保证每次插入都是追加,写数据性能就会提高.
#MySQL
事务之隔离性
当数据库上有多个事务同时执行的时候,就可能出现脏读、不可重复读、幻读等问题,这就需要靠隔离级别来解决.
隔离级别包括:
动是看到的数据是一致的,当然这个事务的变更也对其他事务不可见
MySQL 默认隔离级别是 可重复读,Oracle 是 读提交.
怎么实现事务隔离?
这就会使得一条记录在系统中的同一时刻会有不同的版本,如果视图 A 要得到 1,就必须依次执行下面的所有回滚操作得到
#book
书籍收藏:
#MySQL
一条更新 SQL 的执行流程:
重要的日志模块: redo log
InnoDB 的 redo log 是固定大小的, 比如可以配置为一组 4 个文件, 每个文件的大小是 1GB, 即总容量是 4GB. 从头开始写, 写倒末尾就就又回到开头循环写:
write pos
是当前记录的位置, 一边写一边后移, 写到 3 号文件末尾就会到 0 号文件重新开始check point
是当前要擦除的位置, 同样是循环的, 擦除记录前要把记录更新到数据文件write pos
和check point
之间的空间就是可以用来记录新的操作, 如果这两个值相等就表示不能继续写了, 得先写入一些数据到磁盘(check point
擦除).有了 redo log, InnoDB 可以保证即使数据库发生异常重启, 之前提交的记录都不会丢失 —— crach-safe
重要的日志模块: binlog
binlog有两种模式,statement 格式的话是记sql语句, row格式会记录行的内容,记两条,更新前和更新后都有。
所以执行器和引擎执行更新 SQL 的流程:
prepare
状态. 然后告知执行器执行完成了, 随时可以提交事务commit
状态, 更新完成为什么需要两阶段提交?
#MySQL
一条查询 SQL 的执行过程: