1. MySQL 深入总结
# mysql 集群架构<br>1. master-slave 架构模式<br> 高可用: master 挂了,slave 可提升为 master,对位提供服务。<br>2. 复制模式<br> 异步复制、半同步复制、全同步复制。<br> 异步复制:不需要等待 slave 将 binlog 日志同步到 relay log 中,就提交事务。<br> 半同步复制:需要等待一个 slave 将 binlog 日志同步到 relay log 中,就提交事务。<br> 全同步复制:需要等待所有 slave 将 binlog 日志同步到 relay log 中,就提交事务。<br>3. 复制流程<br> 3.1 从服务器连接主服务器:<br> 从服务器上的 IO 线程通过网络连接主动连接到主服务器。 <br> 从服务器向主服务器发送一个复制请求,该请求包含从服务器所期望的开始位置(binlog 文件和位置)。<br> 3.2 主服务器响应连接请求:<br> 主服务器在接收到从服务器的复制请求后,会为该从服务器启动一个 binlog dump 线程。<br> binlog dump 线程从指定的 binlog 文件和位置开始读取二进制日志。<br> 3.3 主服务器发送 binlog 数据:<br> binlog dump 线程将读取到的二进制日志事件发送给从服务器。<br> 从服务器的 IO 线程接收这些 binlog 数据,并将其写入从服务器的中继日志(Relay Log)。<br> 3.4 从服务器应用 binlog 数据:<br> 从服务器的 SQL 线程从中继日志中读取事件,并逐个将其应用到从服务器的数据库中。<br> <br> 总示意图:<br> 从服务器:<br> 1. IO 线程 --------------> 向主服务器发起连接请求<br> (启动连接)<br> <br> 主服务器:<br> 2. Binlog Dump 线程 -----> 响应连接请求,发送 binlog 数据<br> (传输二进制日志)<br> <br> 从服务器:<br> 3. IO 线程 <-------------- 接收 binlog 数据,写入中继日志<br> 4. SQL 线程 -------------> 从中继日志中读取并应用日志<br> (应用变化)<br> <br> 总结:<br> 尽管主服务器的 binlog dump 线程中扮演了发送日志的角色,但这一过程的启动和驱动是由从服务器主动发起的。 <br> <br># mysql 内部架构<br>1. mysql server 层 + 存储引擎层<br>2. InnoDB 和 MyISAM的区别。<br> 锁的级别:MyISAM 采用表级锁定,一次只能有一个写操作。InnoDB 采用行级锁定,这在高并发写操作的情况下表现得较好。<br> 事务:InnoDB 支持事务,确保数据的一致性和完整性。MyISAM 不支持事务。<br> <br><br># 事务<br>1. 定义 - what<br> 事务(Transaction)是一个数据库操作序列,其中的操作要么全部成功,要么全部失败,保障了数据的完整性与一致性。<br>2. 使用场景 - why<br> 保证业务场景的一致性。<br>3. 事务特性(设计原则):ACID - how<br> 原子性(Atomicity):事务中的所有操作要么全部完成,要么全部不完成,即事务是一个不可分割的工作单元。<br> 一致性(Consistency):执行事务前后,数据库都必须保持一致状态,不允许出现违反数据库约束的状态。比如外键约束。<br> 隔离性(Isolation):一个事务的执行不能被其他事务干扰,各并发事务之间相互独立。<br> 持久性(Durability):一旦事务提交,其结果必须永久保存到数据库中,即使系统发生故障也不能丢失。<br>4. 事务的隔离级别 - how<br> 读未提交(READ UNCOMMITTED):最低隔离级别,允许看到未提交的事务,这会导致“脏读”。<br> 读已提交(READ COMMITTED):一个事务只能看到已经提交的事务,这会导致“不可重复读”。<br> 可重复读(REPEATABLE READ):默认的隔离级别,确保一个事务看到的一致数据快照,避免“不可重复读”。<br> 串行化(SERIALIZABLE):最高隔离级别,确保事务完全串行化地执行,避免“幻读”。<br>5. innodb 存储引擎 各个隔离级别的实现原理 - how<br> RC 和 RR 隔离级别,采用的是 MVCC + 一致性读视图实现,提高了读写并发执行。 详见:https://www.cnblogs.com/DengGao/p/mysql.html<br> RC 隔离级别,每次读的时候,重新生成一份读视图,而 RR 隔离级别,复用第一次生成的读视图。<br><br># 索引<br>1. 定义 - what<br><br>2. 使用场景 - why<br> 加快查询。<br><br>3. 分类 - how<br> 一级索引、二级索引<br> <br>4. 实现原理 - how<br> Innodb 存储引擎使用的是 B+ 树。<br> 因为B树不管叶子节点还是非叶子节点,都会保存数据,这样导致在非叶子节点中能保存的指针数量变少,指针少的情况下要保存大量数据,只能增加树的高度,导致IO操作变多,查询性能变低。<br> <br><br># 锁<br>1. 定义 - what<br><br>2. 使用场景 - why<br> 使用场景:防止并发,产生脏数据。<br> <br>3. 分类 - how<br> 根据锁粒度不同,分为表锁、行锁。粒度越小,并发越高。<br> 控制并发程度不同,分为共享锁、排它锁。排它锁和共享锁、排它锁和排它锁不可以并发执行。<br> 行锁的具体实现:行锁、间隙锁、next-key 锁。<br> <br>4. 对于 mysql innodb 存储引擎,锁的具体使用场景如下 - how<br> 1. 事务里的【写】操作(insert、update、delete),四种隔离级别,都会加排他锁。<br> 2. 事务里的【当前读】操作,四种隔离级别,都会加锁。加锁如下:<br> select * from table where ? lock in share mode; 加共享锁。<br> select * from table where ? for update; 加排他锁。<br> 3. 事务里的【快照读】操作,前三种隔离级别,不会加锁,最后一种隔离级别,会加共享锁。简单的 select 操作,就是快照读。select * from table where ?;<br> 4. 事务里的锁都是同一时刻释放的,就是事务提交或者回滚的那一刻。<br><br>5. 排它锁和共享锁、排它锁和排它锁是不可以并发执行的。<br><br>6. 在读未提交、读已提交和可重复度的隔离级别下,【快照读】是不加锁的,因此并发性能会高不少。<br><br>7. 在RC、RR隔离级别下,为了防止事务等待,我们近可能做到:<br> 7.1 加锁时间要尽可能短。因此使用小事务。<br> 7.2 加锁范围尽可能小。因此where条件尽可能锁定少量行。<br><br># 死锁<br>1. 死锁产生的原因<br> 两个事务循环等待对方持有的锁。比如事务1持有锁A,等待锁B;事务2持有锁B,等待锁A。<br>2. 死锁的解决方案<br> 2.1 预防死锁<br> 小事务:保持事务尽可能短,即减少事务在同一时间段内锁定的资源数量,降低死锁的概率。<br> 按一致的顺序访问资源:确保所有事务按照相同的顺序请求锁定资源,避免循环等待。<br> 设置合理的锁粒度:避免一次性锁定太多的资源,锁的粒度要适当,不要过大。<br> 2.2 检测与处理死锁<br> 当出现死锁,回滚其中一个事务。<br> 2.3 等待超时。<br> 加锁超时后,自动回滚。<br><br># mysql 文件组成以及IO操作流程<br>https://www.cnblogs.com/DengGao/p/12734775.html<br>1. redo log:innodb 存储引擎独有。 写日志优先。 物理日志。<br> 1.1 作用:保证数据持久性、原子性、崩溃恢复。<br> 1.2 相较于直接写数据的方式,存在的意义:<br> 提高性能:写 redo log 比直接写数据文件要快,因为 redo log 采用顺序写入。这样就能加速事务的提交,提升数据库的整体性能。<br>2. undo log:innodb 存储引擎独有。undo log 并不存储当前数据,存储的是修改前的数据快照。逻辑日志。<br> 2.1 作用:回滚、用于RC/RR隔离级别的多版本并发控制,进而提高并发性。<br>3. bin log:mysql server 日志。 逻辑日志。<br> 3.1 作用:主从复制。<br> 3.2 两种模式:<br> statement格式:SQL语句。<br> row格式:行内容(记两条,更新前和更新后)。推荐。<br>4. innodb 为什么采取两阶段提交。redo log 的 prepare阶段 和 commit 阶段。<br> 确保两个日志的一致性,从而保证分布式场景下,主从一致性。<br> 如果 redo log 直接提交,那么事务就不能回滚了。binlog写入失败,会导致从库与主库的数据不一致。<br><br><br># 总结<br>1. 尽可能不使用大事务的原因:<br>影响响应时间:大事务的执行时间较长,会影响系统的整体响应时间,增加事务等待时间,降低用户体验。<br>锁定资源时间长:大事务需要长时间持有锁,这可能导致并发事务等待锁,从而引发锁争用和死锁问题,影响系统的并发性能和吞吐量。<br>回滚代价高:如果大事务中途出现错误或需要回滚,这将导致大量的回滚操作,产生极大的系统开销。这不仅影响性能,还可能导致更多的资源争用问题。<br>日志和内存开销大:事务需要记录日志以保证数据的一致性和持久性。大事务会占用更多的日志空间和内存资源,可能导致数据库的性能下降。<br><br>2. 一条 sql 是如何执行的。(结合 mysql 机构、索引、锁、事务等信息综合阐述)<br>分析器(词法分析、语法分析) ->优化器(寻找适合的索引) -> 执行器(调用存储引擎的接口) -> 写undolog(在修改数据之前,记录 undo log 以用于事务回滚。)-> 变更 buffer pool 中的数据 -> 更新 redo log (prepare 阶段) -> 写入 binlog -> 写入 redo log (commit 阶段)<br><br>3. innodb 存储引擎的 buffer pool 是干啥的<br> 读取数据时主要依赖于缓冲池(Buffer Pool),以提高读取性能。下面详细介绍这一过程:<br> 3.1 检查 Buffer Pool。<br> 当执行一个读取操作时,InnoDB 存储引擎首先会检查缓冲池(Buffer Pool)中是否已经有需要的数据页。缓冲池是一个内存区域,用于缓存经常使用的数据页和索引页。<br> 命中缓冲池: 如果数据页已经存在于缓冲池中,即发生缓冲池命中(Buffer Pool Hit),则直接从缓冲池中读取该数据。这种方式最快,因为数据已经在内存中,避免了磁盘 I/O 操作。<br> 未命中缓冲池: 如果数据页不在缓冲池中,即未命中缓冲池(Buffer Pool Miss),则需要进行以下步骤:<br> 3.2 从磁盘读取数据页<br> 加载数据页: InnoDB 将从磁盘上的数据文件中加载所需的数据页到缓冲池中。这涉及一次磁盘 I/O 操作,通常会比内存访问慢得多。<br> 缓存到 Buffer Pool: 一旦数据页加载进缓冲池,InnoDB 会将其缓存下来,以便后续的读取操作可以直接从缓冲池中获取数据,减少磁盘 I/O 操作。这一机制提升了系统的整体性能。<br> 读取脏页: 在一些情况下,数据页可能在磁盘上与缓冲池中的版本不一致。特别是在存在未刷新的脏页(Dirty Pages)时,读取操作总是读取缓存池中的最新版本数据,即使这些数据还没有被写回磁盘。<br> 3.3 LRU 链表管理<br> 缓冲池中使用类似 LRU(Least Recently Used,最近最少使用)算法的链表来管理数据页的缓存策略。最近使用的数据页会被保存在链表的前端,而较少使用的页会被移到后端。当缓冲池满时,较少使用的数据页将被移出,腾出空间给新加载的数据页。<br> 通过上面的步骤和机制,InnoDB 大幅度提高了数据读取的性能和效率。缓冲池在这个过程中起到了关键作用,它不仅减少了磁盘 I/O 操作的频率,还保证了读取操作能够迅速获得所需的数据。<br> <br> <br>4. 如果查询条件获取的数据量过多,对数据库性能造成影响,甚至 java 进程 oom。怎么处理?<br> 根据查询条件,分场景处理。<br> 1. 如果是 in 查询,比如:select * from 分班记录 where userId in ()。 那么我们可以分批次查询,降低每批次 in 条件里面的元素数量。 <br> 2. 如果是 = 查询,比如:select * from 分班记录 where teacherId = xxx。处理方式如下:<br> 2.1 前端展示场景,可以分页。存在深度分页的问题,如何解决? 解决不了,只能从业务上面解决。<br><br> 深度分页,可能是个伪需求。超过N页,直接拒绝请求。<em id="__mceDel"> 业务场景,筛选条件做限制。也就是说,where 条件再增加一个字段,建立联合索引,刷选出足够少的数据量。</em> 2.2 一个清洗数据的临时 job。分批次按照id进行游标查询,满足条件的记录,批量更新。<br> 2.3 查询 pipe 库,隔离对核心业务的影响。<br> 2.4 mysql 分库。<br> 此分库方式,数据是随机存储到数据库里面,并没有分库的key路由。查询的时候,从多个数据库聚合数据。类似分布式数据库。<br> 2.5 使用分布式数据库。<br><br>5. 如果并发过多,对数据库性能造成影响。怎么处理?<br> 1. mysql 分库。<br> 1.1 此分库方式,数据是按照key路由到数据库。查询的时候,也是按照路由的key找到数据库查询。<br> 1.2 限制并发。比如限流。<br> 2. 多个 slave,读写分离。<br><br>6. mysql 表行数多(比如1亿),有性能问题吗?如果有,如何解决呢<br> 1. 存在性能问题。表是树状结构,数量越大,层级越多。<br> 2. 可以采用分表的方式。<br> <br>7. 有个疑问,对于二级索引,如果叶子节点一个键值对应多个主键,这多个主键是采用什么数据结构存储的呢?来源:https://www.cnblogs.com/DengGao/p/18562438
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!
页:
[1]