-
数据库事务日志:WAL、redo 与 undo 的作用机制
把某一行从 1 改成 2,如果直接改磁盘上的数据页,这是一次随机写。数据库每秒要改成千上万行,数据页在磁盘上的位置又是分散的,全靠随机写会立刻碰到 IOPS 上限。日志的作用就是把这个随机写换成顺序写。 为什么需要 WAL 顺序写和随机写不在同一个量级:机械盘随机写的 IOPS 通常在几百量级,顺序写吞吐可达上百 MB 每秒;SSD 上差距缩小但仍存在,随机写还带来更多写放大。具体数字取决于硬件与
Cache 孙
-
备份与恢复演练:RPO/RTO 的落地
备份脚本每天在跑,日志显示成功,监控面板上一片绿色。直到某天需要真正用它恢复数据的时候,才发现文件是坏的、binlog 有断档、或者恢复出来少了几个小时的记录。备份本身不产生价值, 能被成功用于恢复的备份才产生价值 。 先把两个指标定义清楚 RPO(Recovery Point Objective) :发生故障时,允许丢失多少时间窗口内的数据。回答的是"能丢多少"。 RTO(Recovery Ti
Moon 槐
-
事务与隔离级别:脏读、不可重复读与幻读
ACID 四个字母里,A、C、D 在工程上相对好验证:原子性靠日志回滚,持久性靠刷盘策略,一致性是业务与约束共同保证的结果。真正让人头疼的是 I——隔离性。它的定义本身就带着妥协:完全隔离等价于串行执行,性能不可接受;降低隔离又会引入各种读写异常。工程上的隔离级别,本质是在正确性和并发度之间选一个自己能接受的点。 一、三种读异常的定义 讨论隔离级别之前,先把三个现象区分清楚,它们经常被混用: 脏读
VectorQ
-
数据库连接池原理:连接数不是越多越好
线上服务响应变慢,第一反应往往是"连接池不够用,调大最大连接数"。调完可能确实缓解,也可能更慢,甚至把数据库拖垮。连接池的参数不是孤立的,它连接的是应用侧并发模型与数据库侧执行模型两端。理解两端的成本结构,才能知道连接数该定多少。 一条连接的建立代价 应用发起一次新建连接,走完的流程大致是: 客户端 服务端 |--- TCP SYN -------->| |<-- SYN+ACK --------
Schema 李
-
时序数据库入门:写入模型与降采样
监控系统每秒采集几十万个指标点,把这些点塞进关系库里,一个月后表会撑到无法维护。时序数据有自己的形状:写多、几乎不更新、按时间追加、查询几乎总是时间范围加几个维度过滤。针对这种形状专门设计的存储引擎,与通用行存的取舍差异很大。 时序数据的四个特征 写多且几乎不更新 。数据点是设备或探针在同一时刻的状态快照,写入之后不会再被修改。偶发的更正以新数据点的形式出现。 按时间追加 。新数据的时间戳总是接近
逻辑熵 Logic
-
读写分离与主从延迟:一致性的工程处理
读写分离通常是数据库扩展的第一步:写走主库,读分摊到多个从库。收益立竿见影,问题也很隐蔽——主从之间的数据不是同步到达的,业务读到的可能是几毫秒前的旧数据。多少业务能容忍这个"旧",是设计阶段必须回答的问题。 复制链路的基本模型 以 binlog 复制为例,一条写操作从主库到从库可见,需要经过三段: 主库 ──1──> binlog 落盘 ──2──> Dump 线程推送 ──3──> 从库 IO
江眠
-
慢查询优化:从 EXPLAIN 开始排查
慢查询排查是个有固定套路的活:先从慢查询日志里找到嫌疑人,用 EXPLAIN 看它打算怎么执行,判断问题出在索引、写法还是表结构上,改完再验证。整条链路里,EXPLAIN 是承上启下的一步——它不能告诉你语句有多慢,但能告诉你为什么慢。这篇文章把这条链路的每一环拆开讲。 一、慢查询日志:先把嫌疑人找出来 MySQL 默认不记录慢查询,需要显式开启: SET GLOBAL slow_query_lo
Elowen
-
MySQL 索引入门:B+ 树、联合索引与最左前缀
索引是数据库性能问题里被讨论得最多、也最容易被误解的一层。很多线上慢查询的根因不是"没加索引",而是"加了索引但没用上",或者"用了索引但代价比想象中高"。想把索引用明白,得先理解它在磁盘和内存之间是怎么组织数据的,再回头看 SQL 语句里那些看似随意的写法如何影响优化器的决策。 一、为什么是 B+ 树 关系型数据库的索引要解决的核心矛盾是:数据量远大于内存,而每一次磁盘随机读的代价都很高。设计目
逻辑熵 Logic
-
用内容哈希做重复文件检测:从思路到实现
磁盘清理里最实在的一块是找重复文件:照片导了两遍、下载目录和文档目录有同一份 PDF、备份目录里躺着历史版本的全家福。按文件名找是不可靠的,按内容找才准——而"按内容"这件事,工程上就是哈希。这篇文章把重复文件检测的完整思路走一遍,从筛选策略到索引设计,再到清理的安全流程。 一、文件名不可靠,内容才算数 重复文件的定义是"内容完全相同的文件",而不是"名字相同的文件"。现实中的重复文件形态五花八门
雾梨 Mist
-
NoSQL 选型思考:文档、键值与关系型的边界
"NoSQL" 这个词覆盖面很宽,键值存储、文档库、列族数据库、图数据库都算,彼此之间的差异比它们和关系型数据库之间的差异还要大。讨论选型时如果说"我们要用 NoSQL",这句话本身几乎不含信息量。真正有用的问题是: 这个业务问题的数据访问模式是什么,哪一类存储引擎的原生语义和它最接近 。 一、CAP 与 BASE 的工程视角 CAP 定理说分布式系统在分区发生时要在一致性(C)和可用性(A)之间
苏念禾
-
Redis 数据结构实战:五种基础类型的使用场景
Redis 的价值不在于"快"本身,而在于它把一组精心挑选的数据结构放在了内存里,并且保证了单个命令的原子性。用好 Redis 的关键,是让业务模型尽量贴合这些结构的原生语义——一旦发现需要在客户端把多个命令拼成一个"复合操作",就该停下来想想选型是不是出了问题。 一、五种基础类型怎么用 String 是最简单的类型,但能力不止存字符串。它可以存整数做计数器,也可以序列化整个对象存成 JSON(慎
码同客
-
大表 DDL 的在线变更方案
给一张几百 GB 的表加个字段,开发以为是一行 SQL 的事,DBA 知道这可能是几小时的磁盘 IO 和一次业务抖动。搞清楚 DDL 背后的执行路径,才能判断一次变更到底需要多少资源、会不会阻塞业务。 DDL 为什么会锁表 原因有两类。 第一类:元数据锁(MDL) 。任何访问表的语句(包括 SELECT)都会持有该表的 MDL 读锁,DDL 需要 MDL 写锁。两者互斥。这意味着: 一个长时间运行
Elowen
-
执行计划进阶:JOIN 顺序与驱动表选择
一条三表 JOIN 的慢查询,加索引之后可能依然很慢。原因往往不在索引本身,而在优化器挑选了错误的驱动表或者 JOIN 顺序——一旦外层产生的结果集远大于预期,内层的索引再好,也只是被执行了更多次。 优化器是怎么挑 JOIN 顺序的 对于一张 join 涉及到的表,可选的执行顺序数量随表数呈阶乘增长。优化器不会穷举所有组合,通常采用基于成本的贪心搜索(MySQL 的实现带有深度限制),对每个候选顺
朔风
-
数据库迁移:跨库数据同步与一致性校验
迁移的困难不在搬数据,而在搬的过程中源库还在被写入。两边同时有写入,就必须在"业务不能停"和"数据不能错"之间找一条可执行路径。所有迁移方案本质上都在安排这两件事的顺序。 三类场景,难度差很多 场景 典型动因 主要难点 可行路径 同构升级 版本升级、硬件更换、上云 停机窗口、版本兼容性 主从切换,相对简单 异构迁移 换数据库类型、换存储引擎 类型映射、SQL 语义差异、性能特性变化 双写 + 校验
雾梨 Mist
-
JSON 字段与半结构化数据的存储取舍
现代关系库都提供了原生 JSON 类型:MySQL 的 JSON 、PostgreSQL 的 jsonb 。它让"先上线再说"变得非常容易——不用改表结构就把业务属性塞进去了。问题是这类字段用久了,往往会变成查询瓶颈的来源,而改造成本随数据量增长。 什么时候 JSON 字段是合理的 属性稀疏且差异大 。不同品类的商品有不同的规格:手机有屏幕尺寸和内存,衣服有尺码和面料,图书有 ISBN 和页数。如
Cache 孙
-
分库分表的时机与代价
数据量涨到一定规模,团队会开始讨论要不要分库分表。这个决定几乎不可逆——一旦上线,路由逻辑、运维方式、故障排查路径都会改变。动刀之前值得先把"为什么现在要拆"和"不拆还有什么办法"想清楚。 先确认真的需要拆 单表变大带来的压力,很多时候不是非靠拆分不可。下面这些手段应当先被逐一评估: 手段 解决什么问题 代价 索引优化、覆盖索引 慢查询、回表过多 写放大、占用空间 读写分离 读压力远大于写压力 主
江眠