对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁(X)
IN SHARE MODE 共享锁(S) FOR UPDATE 排他锁(X) 行锁解决两个事物同时更新
读未提交: 脏读:读到了其他事务未提交的数据 例如修改,新增数据
读已提交: 不可重复读:一个事务内,多次读取的数据不一致 读到了其他事物已提交的数据!!! 比如修改同一个账户,添加了新的数据
可重复读: 幻读:多次读取查询到不同的结果集 其他事物的insert (默认)
序列化:强制事务排序
解决幻读 Mvcc+行锁+间隙锁 左开右闭原则,(-∞,5](5,10](25,+supernum]
BigDecimal 存钱 double加钱会存在精度问题
//START TRANSACTION;
// UPDATE users SET balance = balance - 100 WHERE id = 1; //扣钱不能先读出去,在修改 除非修改值方法都在同一个lock里面
//-- 如果此时另一个事务也尝试更新id为1的用户数据,则会出现问题
// COMMIT;
// where条件一定要存在!!!不然存在大问题
if (lock.tryLock()) {
//获取锁后一定要释放
try {
} catch (Exception e) {
throw new AppException(e.getMessage());
} finally {
lock.unlock();
}
}
sql执行顺序
from,join来确定表之间的连接关系,得到初步的数据 不加关联条件会出现笛卡尔积
where再group by 再having语法支持聚合函数
select order by limit需要的记录数时,就不继续往下查
cdn 找到最近缓存有效的机器快速返回 有效的负载均衡!! 减少了主服务器的压力。 但是经常更新的会导致源站的压力
如果在用户访问高峰期,图片内容大批量发生变化,大量用户的访问就会穿透cdn,对源站造成巨大的压力。
接口性能
索引优化force index sql优化 远程调用多个异步 数据异构多个数据结构放在redis里面 重复调用mysql 死循环发现!! 线程池 mq 分库分表 加监控Prometheus整体监控 skywalking链路追踪
mysql深度分页
比如你要查询 300w开始后面10条数据;mysql会读取300w加10条这么多的数据,只不过 过滤后返回最后10条而已!!!
如果有索引 不会查这么多 但是也会很慢
第一种简单粗暴,就是不允许查看这么靠后的数据
第二种方法,在查询下一页时把上一页的行id作为参数传递给客户端程序,然后sql就改成了
select from table where id>3000000 limit 10; table的主键id是自增的 select * from table where id>10010 limit 10;
最后第三种方法:延迟关联 select * 数据太多
select table. from table inner join ( select id from table limit 3000000,10 ) as tmp on tmp.id=table.id;
连接器验证 查询缓存 分析器 优化器 执行器 存储引擎
写入redo(prepare阶段)->写入binlog->提交事务commit 两阶段提交
当有数据修改时,会先将修改redo log cache和binlog cache然后在刷入到磁盘形成redo log file,当redo log file全都刷入到磁盘时(prepare 状态)和提交成功后才能将binlog cache刷入磁盘,当binlog全部刷新到磁盘后会记录一个xid,然后在relo log file上打上commit标志(commit阶段)。
mysql拉去数据过程 binlog undolog redolog
binlog 记录数据库执行的写入性操作(不包括查询)信息,以逻辑日志二进制的形式保存在磁盘中。 !!!Server层进行记录,使用任何存储引擎的 mysql 数据库都会记录 binlog 日志。为了所有引擎都能复制
binlog 是通过追加的方式进行写入的,可以通过max_binlog_size 参数设置每个 binlog文件的大小,当文件大小达到给定值之后,会生成新的文件来保存日志。
逻辑日志:可以简单理解为记录的就是sql语句 。
物理日志:mysql 数据最终是保存在数据页中的,物理日志记录的就是数据页变更 。
redo log是为了实现事务的持久性!!!InnoDB存储引擎层的日志,又称重做日志文件,用于记录事务操作的变化,记录的是数据修改之后的值,不管事务是否提交都会记录下来!!
是物理日志,记录该数据页更新的内容 它用来恢复提交后的物理数据页(恢复数据页,且只能恢复到最后一次提交的位置)。
Undo Log是为了实现事务的原子性!!!.系统可以利用UndoLog中的备份将数据恢复到事务开始之前的状态。
undo log主要记录了数据的逻辑变化!!!,比如一条 INSERT 语句,对应一条DELETE 的 undo log !!!,对于每个 UPDATE 语句,对应一条相反的 UPDATE 的 undo log ,这样在发生错误时,就能回滚到事务之前的数据状态。同时, undo log 也是 MVCC(多版本并发控制)实现的关键。
服务端并不需要保存一个完整的结果集,取数据和发数据的流程是这样的:!!!! mysql是”边读边发的”
–1 获取一行,写到net_buffer中,这块内存的大小是由参数net_buffer_length,默认16k
–2 重复获取行,直到net_buffer写满,调用网络接口发出去!!!
–3 如果发送成功,就清空net_buffer,然后继续取下一行,并写入net_buffer
如果发送函数返回eagain或者wsaewouldblcok,就表示本地网络栈(socker send buffer)写满了,进入等待,直到网络栈重新可写,再继续发送
mysql只会走一个索引 会判断走那个索引,太久就会走全表! https://blog.csdn.net/weixin_39907133/article/details/113286189
查询索引找到符合的叶子节点(存的是主键key) 再从主键索引!!!主键key中拉取想要的数据 这个过程叫做回表!!!
节点里存的是 user_name 这个 KEY,叶子节点存储的数据的是主键 KEY!!!!!! 存的是整行数据
比如说user_name是个索引,当执行该SQL:select * from user_info where user_name
= ‘xiaoming’; InnoDB 就会建立 user_name 索引 B+树,节点里存的是 user_name 这个 KEY,叶子节点存储的数据的是主键 KEY。注意,叶子存储的是主键 KEY!拿到主键 KEY 后,InnoDB 才会去主键索引树里根据刚在 user_name 索引树找到的主键 KEY 查找到对应的数据
InnoDB 只在主键索引树的叶子节点存储了具体数据,但是其他索引树却不存具体数据呢 而要多此一举先找到主键,再在主键索引树找到对应的数据呢!!!
InnoDB需要节省存储空间。一个表里可能有很多个索引,InnoDB都会给每个加了索引的字段生成索引树,如果每个字段的索引树都存储了具体数据,那么这个表的索引数据文件就变得非常巨大(数据极度冗余了)。从节约磁盘空间的角度来说,真的没有必要每个字段索引树都存具体数据
mysiam是一个数据索引 一份数据文件 任何请求都直接得到id,再到文件去查询 索引只适合读,不适合事务!!!也不支持外键 多个索引表对应数据文件,不可能去锁所有索引表,只有锁文件表!!!
innodb主键索引存所有数据,然后叶子节点存数据,所以支持行锁!!!! 因为所有数据最终都会用到主键索引。
优化点!!!!! 查询慢 返回的数据多 或者 二次查询!!
建一个联合索引 (a,b,c) ,实际相当于建了 (a)、(a,b)、(a,b,c) 三个索引。
覆盖索引是select的数据列只用从索引中就能够取得,不必读取数据行,换句话说查询列要被所建的索引覆盖。!!!!!
select * 慢的原因!!!
1.可能辅助索引就能满足,不用二次查询
2.查询出了不想要的数据,增加了io和返回数据网络开销!!!
3.对于无用的大字段,如 varchar、blob、text,会增加 io 操作!!!!!长度超过 728 字节的时候,!!!会先把超出的数据序列化到另外一个地方,因此读取这条记录会增加一次 io 操作!!!
可以把大字段在拆分表,多一次查询!!!
explain查看执行计划,可以看到Using temporary 用到临时表就意味着性能较低 省空间。私密性 高效率。
临时表 UNION查询; ORDER BY和GROUP BY的子句不一样时; DISTINCT查询并且加上ORDER BY时; FROM中的子查询; join 包括not in、exist等
视图是虚表
索引大小
select
database_name,
table_name,
index_name,
round((stat_value*@@innodb_page_size)/1024/1024, 2) SizeMB,
round(((100/(SELECT INDEX_LENGTH FROM INFORMATION_SCHEMA.TABLES t WHERE t.TABLE_NAME = iis.table_name and t.TABLE_SCHEMA = iis.database_name))(stat_value@@innodb_page_size)), 2) Percentage
from mysql.innodb_index_stats iis
where stat_name=‘size’
and table_name = ‘base_apt’
and database_name = ‘ag_security_db’
base_apt.ibd 数据加索引文件
索引在磁盘上。要减少io!!先读索引第一行将磁盘块1加载到内存中! 第二次 将磁盘块2加载到内存中 第三次IO:将磁盘块6加载到内存中取出数据!!!
数据重复且分布平均的字段,因此他建立索引就没有太大的效果(例如性别字段,只有男女,不适合建立索引)
数据变更需要维护索引,意味着索引越多维护成本越高。 更多的索引也需要更多的存储空间
https://blog.csdn.net/weixin_37641832/article/details/103217311
磁盘存储概念;一个磁臂 多个盘片 一个盘片一个磁头
磁道:指的是第几圈 扇区:指的是盘片的一部分,磁盘块,存的数据大小一样,索引里面密度更高
可用(柱面号,盘面号,扇区号)来定位任意一个“磁盘块”!!
mysql对索引这个节点大小设置的是16K!!!!! 4K对齐读写效率更高!!!!!!! 不浪费空间 而且对齐
Bigint,8bit,下一个节点的地址,mysql分配的是6bit 16K的节点可以存多少对也就是多少个索引,8b+6b=14b,16K /14b=1170个索引 叶子节点有索引有data元素,假设占1K,那一个节点就放16K/1K=16个元素 假设树高是3,所有节点都放满,能放多少数据?可以算一下,1170117016=21902400,2千多万
cpu的多级缓存 为了解决CPU的频率太快,以至于主存!!(一个)跟不上 多个cpu多个缓存,提前把要的数据加入到缓存中
多线程 缓存一致性问题,用到同一个主存地址,但是缓存值不一样 (共享变量存放在主内存中) 指令重排序问题
Java内存模型(JMM) JMM通过控制主内存必须与每个线程的本地内存之间的交互!!!!!!保证了可见性