简介这套MySQL与SQL学习资料面向数据库初学者及Web开发人员系统覆盖从环境搭建、建表、增删改查、聚合分组到多表联结、子查询、视图、存储过程、触发器、事务与索引等核心知识点同时包含查询优化、表结构设计及备份恢复等进阶内容并延伸至MySQL 8新特性适合零基础入门和日常复习。压缩包共41个文件以20个PDF讲义和19个SQL脚本为主另有2个Markdown说明其中PDF按章节拆解知识要点SQL文件对应具体练习与示例代码整体仅21.88MB便于下载后按编号顺序学习。当前已有221人学习使用。相比零散教程这套资料将完整课程笔记与可运行脚本组合在一起读者既能对照PDF理解原理也可在MySQL中直接执行SQL脚本验证结果并可通过实际数据库设计案例了解与PHP、Python、Java的集成方式能有效提升数据库管理与Web应用开发能力无论日常练习还是项目实战都很有帮助。1. 知识地图MySQL学习不是背命令而是建体系MySQL学到最后真正拉分的地方不在背了多少条SQL而在能不能把散落的知识串成一张网。很多人把语法当成全部结果一遇到索引失效、死锁、主从延迟就发懵。这张网应该是这样的存储引擎决定数据怎么组织和恢复索引决定查询怎么加速事务和锁决定并发写入怎么不错优化工具决定慢查询怎么定位主从复制决定架构怎么扩展。这份MySQL学习资料就是按这条主线整理出来的。它适合两类读者系统入门的人按顺序吃透正在复习备考的人直接用每章最后的问题自查。先记住这条主链往后每一步都会回到它。2. 从SQL到存储引擎先打通数据操作主线2.1 语法内核DQL怎么写才不白学SQL按用途分四类DDL建表、改表、DML增删改、DQL查询、DCL权限。绝大多数学习资料的篇幅都压在DQL上不是因为DQL语法多而是因为它背后有一套执行顺序。书写顺序是SELECT FROM WHERE GROUP BY HAVING ORDER BY LIMIT执行顺序却是FROM WHERE GROUP BY HAVING SELECT ORDER BY LIMIT。这个差异如果不亲手验证后面写复杂报表时就会频繁犯“别名用了没生效”的错。来看一条典型的分组查询SELECT dept_id, COUNT(*) AS cnt FROM employee WHERE hire_date 2024-01-01 GROUP BY dept_id HAVING cnt 5 ORDER BY cnt DESC LIMIT 5;这条SQL在MySQL 5.7及以上会直接报错因为HAVING发生在SELECT之前看不到cnt这个别名。正确写法是HAVING COUNT(*) 5。执行顺序里FROM先生成虚拟表WHERE过滤行GROUP BY分组HAVING过滤组SELECT投影列ORDER BY排序LIMIT取前N条。理解这个顺序后LIMIT和OFFSET的参数也清楚了LIMIT 5表示取5条LIMIT 10,5表示跳过10条再取5条OFFSET是第二个参数而不是第一个。复习DQL时有个高性价比动作找3条慢SQL在右侧标注每一步执行时数据量怎么变化。比如一条SQL先WHERE过滤掉90%行再GROUP BY那么分组压力就小如果先GROUP BY再HAVING则分组阶段要处理全部行。标完你自然就看懂了为什么HAVING过滤不如WHERE提前过滤。DML同样值得警惕。UPDATE和DELETE执行前先EXPLAIN已经是我见过最可靠的防翻车习惯。比如UPDATE accounts SET balance balance - 100 WHERE status 3;如果status上没有索引InnoDB为了找到这些行只能做全表扫描并且扫描期间会锁住更多的行严重时直接造成线上阻塞。很多生产事故不是语法错而是“能跑但锁太多”。所以我的建议是UPDATE/DELETE之前先跑一条SELECT确认影响行数和执行计划再加上事务和LIMIT如果业务允许控制影响范围。2.2 存储引擎对比InnoDB与MyISAM的取舍存储引擎的差异决定了“数据放哪里、怎么取、能不能并发写”。InnoDB和MyISAM最本质的差别在索引和数据的组织方式。InnoDB用聚簇索引主键索引的叶子节点直接保存整行数据因此主键查询极快但二级索引的叶子保存的是主键值查询时先找到主键再回表取整行。MyISAM用非聚簇索引数据文件独立存放索引文件里保存的是指向数据行的指针完全不需要回表。特性主索引事务锁粒度外键崩溃恢复InnoDB聚簇索引支持行锁支持依赖redo log重启自动恢复MyISAM非聚簇索引不支持表锁不支持崩溃后需手动修复容易丢数据为什么要掌握这个对比因为面试最常问的“什么时候不用InnoDB”能从这里推出来。MyISAM的读性能在某些点查场景下因为有独立索引文件历史上有优势但它不支持事务、崩溃后难恢复所以OLTP业务几乎不用。读多写少、容忍丢失最近写入数据的分析临时表才可能考虑MyISAM。5.7之后默认引擎就是InnoDB很多新人不理解为什么还有MyISAM实际是为了兼容老库和特殊归档场景。查看当前库的表引擎一条命令就够SELECT table_name, engine FROM information_schema.tables WHERE table_schema test;也可以SHOW TABLE STATUS LIKE orders\G在Engine列看到引擎名。如果发现某张表的引擎不对ALTER TABLE orders ENGINEInnoDB;可以转换。但转换操作会在原表上重建数据量大时要评估在线时长学习资料里提到的在线变更工具思路是大表变更的后悔药正式环境要考虑工具链而不是直接执行ALTER。除了这两个MEMORY引擎把数据放内存适合session级的临时表但重启后数据清空ARCHIVE引擎支持高压缩插入只能顺序读适合日志归档。学习阶段只需要知道它们存在不要把它们和真正的业务表混用。2.3 索引为什么是复习的重头戏索引部分是MySQL体系里最值得花时间的地方。底层结构几乎只考B树我提炼三个特征叶子节点存数据并且用双向链表串联所以区间查询不用回溯非叶子节点只存索引键单页能放大量键树高通常只有3层左右每个节点都保持键有序插入删除需要维护平衡。相比哈希索引B树能做范围查询这是它成为InnoDB主索引结构的原因。哈希索引只有等值匹配Memory引擎支持但业务上很少用来做主索引。联合索引是最容易出题的点。看下面这个经典建表CREATE TABLE orders ( user_id INT NOT NULL, status TINYINT NOT NULL, created_at DATETIME NOT NULL, KEY idx_user_status_time (user_id, status, created_at) );对WHERE user_id1 AND status2 AND created_at2024-01-01优化器完全走这个联合索引对WHERE status2因为跳过了最左列user_id索引失效。参数说明最左前缀不是在SQL里写了最左边的字段就够而是索引定义顺序的前缀。MySQL优化器可以重排WHERE条件的等值条件但无法补齐缺失的最左列。回表、覆盖索引、索引下推ICP是三个相邻概念建议连在一起复习。二级索引的叶子不存整行查询超过索引列以外的字段就需要回表如果SELECT列表正好都是索引列则只需扫描二级索引就能搞定Extra显示Using index这就是覆盖索引MySQL 5.6之后的索引下推则把WHERE中能下推到索引的条件提前过滤减少回表次数。比如WHERE user_id1 AND status1在索引内先滤掉status1的记录再回表这就是ICP。索引不是越多越好。每张表每多一个索引写入时就要多维护一棵B树。如果一张表有5个二级索引插入一行可能要写6棵树。低基数的列也不要建比如state只有0和1两个值优化器大概率选择全表扫描索引成了摆设。主键设计也建议自增整型严格有序的插入能让B树叶子顺序追加避免随机主键触发页分裂这是很多学习资料在索引一章的最后一个结论。3. 事务与锁并发一致性的三大考点3.1 事务ACID与隔离级别的对照表事务是InnoDB支持并发安全的基础。ACID四个字母每个背后都有具体机制原子性靠undo log出事回滚一致性靠业务约束和数据库检查约束事务只能保证在约束下从一个一致状态到另一个一致状态隔离性靠锁和MVCC持久性靠redo log掉电后重放恢复。很多人在一致性上犯错把一致性当成数据库的魔法其实一条转账SQL如果业务逻辑只减不加数据库再强也补不出钱。隔离级别解决并发读写的三个问题脏读读到未提交数据、不可重复读同一条记录两次读不一样、幻读同一个范围两次读的行数不一样。它们的对照关系是面试必问的隔离级别脏读不可重复读幻读读未提交可能可能可能读已提交不可能可能可能可重复读InnoDB默认不可能不可能可能InnoDB通过MVCC间隙锁消除串行化不可能不可能不可能注意表格里“可重复读”一格的注释标准SQL规范认为RR会幻读但InnoDB借助MVCC普通读和临键锁当前读实际上抹平了常见幻读所以复习时不要死背标准答案要补一句MySQL的实现差异。查询和修改隔离级别的SQL要刻意练一下SELECT global.transaction_isolation, session.transaction_isolation; SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;8.0里变量是transaction_isolation早期版本叫tx_isolation。如果拿旧笔记在8.0执行SELECT tx_isolation直接报语法错误这是版本坑。事务测试时要记住先BEGIN再查询否则每条SQL自动提交隔离级别测试没有意义。为什么MySQL默认用可重复读在MySQL 5.0之前binlog只有statement格式如果用读已提交主从复制时同一个事务里先UPDATE又SELECT从库重放结果可能不一致RR配合间隙锁让复制语义更确定。后来binlog的row格式普及RC也越来越多地用在生产。复习时可以记住一句话隔离级别没有绝对优劣默认RR是历史沿革加MVCC的实现选择业务场景决定用哪个。3.2 锁的类型与死锁排查思路锁是隔离性的执行手段。从粒度分有表锁、行锁、间隙锁、临键锁从读写模式分有共享锁和排他锁。SELECT本身是快照读不加锁SELECT ... FOR UPDATE、UPDATE、DELETE是当前读必须加行锁。如果WHERE条件不能走索引InnoDB就可能从行锁退化成表锁这是一个非常隐蔽的线上雷。间隙锁只在可重复读下发挥作用。比如事务A执行SELECT * FROM orders WHERE amount BETWEEN 1000 AND 2000 FOR UPDATE;此时没有一条订单的amount落在[1000,2000]区间InnoDB会在(1000,2000)这个范围加间隙锁阻止别的事务把amount1500的新订单插进来直到A提交。所以RR下“范围当前读”会锁定一个空区间不要以为查不到数据就没有锁。死锁排查是运维高频题。先看一个最经典的死锁场景-- 事务1先抢id1再抢id2 UPDATE accounts SET balance balance - 100 WHERE id 1; UPDATE accounts SET balance balance 100 WHERE id 2; -- 事务2先抢id2再抢id1 UPDATE accounts SET balance balance - 100 WHERE id 2; UPDATE accounts SET balance balance 100 WHERE id 1;两个事务各自握住一把行锁又都在等对方的另一把锁形成循环等待。InnoDB会检测到死锁并回滚其中一个但业务层会收到不友好的错误。排查命令SHOW ENGINE INNODB STATUS;输出中LATEST DETECTED DEADLOCK段会记录两个事务各自执行的SQL、等待的锁、被回滚的是谁。参数说明这段只保留最近一次死锁信息想要历史记录需要开启innodb_print_all_deadlocksON把每次死锁写到错误日志。避免死锁的通用手段是让所有事务按同一个顺序访问行比如统一先按id升序更新再加一条把大事务拆小减少持有锁的时间。如果业务能接受版本号方式乐观锁可以避免加锁等待UPDATE accounts SET balance balance - 100, version version 1 WHERE id 1 AND version 3;影响行数为0说明版本被改需要重试。这不是MySQL锁但面试经常和悲观锁放在一起问复习时顺便整理进对比表。3.3 MVCC读不加锁的底层原理MVCC是InnoDB实现可重复读和读已提交的核心。每一行记录上隐藏着两个关键列DB_TRX_ID最近修改这行的事务id和DB_ROLL_PTR指向undo log中旧版本的指针。UPDATE一行并不直接覆盖而是先生成旧版本链再写入新版本旧版本留在undo log里。当事务开始第一次SELECT时会生成一个read view快照里记录着当时所有活跃事务的id集合。判定某个版本对当前事务是否可见规则可以简化成三步如果版本的trx_id小于read view的最小活跃事务id说明修改这个版本的事务早已提交可见如果trx_id在活跃事务id列表中说明修改这个版本的事务还没提交不可见沿回滚指针找旧版本如果trx_id大于最大活跃id说明版本来自“未来”不可见。这套规则让普通SELECT完全不需要加锁也能拿到一个一致的历史快照这就是“读不加锁”的来源。举个例子。事务A开启后查询一行得到值v1事务B更新这行并提交得到v2A再次普通SELECT因为read view没有变A看到的仍然是v1。如果A执行SELECT ... FOR UPDATE走的是当前读看到的是最新v2同时加行锁。这解释了RR下为什么同一行多次读一致也解释了为什么FOR UPDATE和普通SELECT结果可能不同——两者根本不在一个版本读取路径上。MVCC和隔离级别的关系是复习时最容易忽略的读已提交每次SELECT都会生成新的read view所以能看到其他事务已提交的新版本可重复读只生成一次read view后续SELECT复用读未提交干脆不建read view直接读最新版本串行化改成锁定读不用MVCC。因此说“可重复读下没有幻读”要分成两半普通读因为快照看不到新插入的行当前读因为临键锁挡着新插入的行合起来才成立。把这条主线捋顺并发这块的核心就掌握得差不多了。4. 性能优化EXPLAIN、慢查询与索引失效4.1 EXPLAIN各字段怎么看EXPLAIN是排查慢查询的第一工具但很多人只看type忽略Extra结果二次踩坑。先看一条完整执行计划EXPLAIN SELECT o.id, o.amount, u.name FROM orders o JOIN users u ON o.user_id u.id WHERE o.status 1 AND o.created_at 2024-01-01 ORDER BY o.created_at DESC LIMIT 10;关键字段按重要程度排type代表访问类型从好到坏大致是system const eq_ref ref range index ALL。system/const说明主键或唯一索引命中了单行eq_ref常见于连接查询中的被驱动表按主键取行ref是普通索引等值匹配range是索引范围扫描比如、BETWEENindex表示扫描整个二级索引的叶子ALL是全表扫最需要警惕。见到index或ALL先别急着加索引要把前面的条件一起看。key列是实际选的索引possible_keys是优化器候选。rows是优化器估算需要扫描的行数它是采样结果不精确但能反映量级。Extra列的信息密度最高Using index说明覆盖索引全查询不用回表这是最理想的情况Using where说明存储引擎返回后再过滤如果同时有索引一般是索引没能覆盖全部过滤条件Using filesort意味着ORDER BY没法用索引排序MySQL专门分配内存甚至临时文件排序是很多慢ORDER BY的真凶Using temporary说明使用了临时表来完成GROUP BY或DISTINCT常见于字段没跟上索引。与其死记字段解释不如做一次“观察实验”给一张100万行的订单表分别建单列索引和联合索引对比下面两条SQLEXPLAIN SELECT * FROM orders WHERE status 1 ORDER BY created_at DESC;如果只在status上建索引回表后ORDER BY的created_at无法从索引取Extra出现Using filesort如果建(status, created_at)联合索引ORDER BY能按索引顺序读取filesort消失。同时key_len也值得看它是索引中被使用的字节长度跟字符集有关varchar(255)的utf8mb4列key_len可能达到255*42通过它你能判断联合索引到底用了哪几列这比反复猜哪里失效直接得多。4.2 慢查询日志与优化流程慢查询日志是发现问题的入口。开启方式SET GLOBAL slow_query_log ON; SET GLOBAL long_query_time 2; SET GLOBAL slow_query_log_file /var/log/mysql/slow.log;参数说明long_query_time单位是秒2表示执行超过2秒的SQL才落日志文件路径要保证mysqld进程有写权限否则日志不生效。这些是会话级设置重启后失效正式环境要写入my.cnf的[mysqld]段。查看各客户端当前变量用SHOW VARIABLES LIKE slow_query%;。拿到慢SQL后的优化闭环是定位慢SQL → EXPLAIN → 明确type/rows/Extra → 建索引或改写 → 复测耗时与rows。下面这条来自一个订单分析系统SELECT user_id, COUNT(*) FROM order_log WHERE source app AND create_date BETWEEN 2024-05-01 AND 2024-05-31 GROUP BY user_id;第一次EXPLAIN的结果是typeALLrows500万Extra里有Using where和Using temporary。原因是source和create_date都没索引GROUP BY也走了临时表。先加联合索引ALTER TABLE order_log ADD INDEX idx_source_date (source, create_date);再次EXPLAINtype变成rangerows降到几万但Extra仍然有Using temporary因为GROUP BY user_id无法直接用该索引完成分组。如果业务确实需要这个统计进一步把索引扩成(source, create_date, user_id)让user_id进入索引Extra变成Using index覆盖了整个查询临时表也就没了。这个案例展示了一个容易被忽略的原则优化不是一次到位而是每改一步都重新EXPLAIN看rows和Extra有没有变。另外慢日志里常见的不是一条SQL而是一个模板的多种参数。比如WHERE city_id?的模板可能被不同页面反复调用。先优化模板本身的索引比逐条处理效率高得多。最后不要只信执行时间线上抖动和缓存都会造成假象用慢日志分析工具按执行次数和总时长排序能快速排出优先级。4.3 索引失效的典型场景索引失效是性能优化里最“玄学”的板块其实背后都是同一个原理让索引列失去有序性。下面这张清单建议背下来每一条都能对应一个实际翻车现场场景示例失效原因对索引列做函数运算WHERE DATE(created_at)2024-01-01每一行都要算完才能比较B树无法二分隐式类型转换WHERE phone13800138000phone是string字符串被转成数字索引列隐式函数运算LIKE以%开头WHERE name LIKE %张中缀/后缀无法匹配前缀有序联合索引缺失最左列idx(a,b,c)WHERE b1无法在树里定位a分支OR连接了非索引列WHERE a1 OR d2d无索引无法统一扫描策略优化器选全表函数运算可以用改写来救DATE(created_at)改用范围条件WHERE created_at 2024-01-01 AND created_at 2024-01-02type会从ALL变range。LIKE %张如果业务确实需要后缀匹配可以考虑反转列存或者用生成列STORED GENERATED COLUMN索引但对大多数系统来说正确方案是换搜索引擎或接受扫描硬用函数索引MySQL 8.0支持要注意兼容性。OR导致失效也有例外如果OR两边的列都有索引优化器可以用union合并索引结果但这种情况性能往往不如预期不如拆成两条SQL再聚合。另外是统计相关列值分布极度均匀或NULL占比过高时优化器宁可扫全表也不走索引因为走索引的回表开销更大。验证每一类失效场景最快的方法是造数据EXPLAIN SELECT * FROM employee WHERE DATE(hire_date) 2024-06-01; EXPLAIN SELECT * FROM employee WHERE hire_date BETWEEN 2024-06-01 AND 2024-06-01 23:59:59;对比两条SQL的type和rows能亲手看到的差异比背十遍都管用。5. 易漏/易错点MySQL学习中常被忽略的五处5.1 字符集与排序规则默认值易漏点建库建表不指定字符集默认值埋下乱码和排序隐患。为什么漏本地练习时数据量小看不出影响等到导入旧库脚本、或把连接从5.7迁到8.0才发现中文变问号、emoji直接报错、ORDER BY排序结果和预期不一样。MySQL 5.7的默认库可能是latin18.0默认是utf8mb4不同版本默认值不一样依赖默认值本身就是在赌运气。怎么补建库建表时把字符集写死一行代码做到可复现CREATE DATABASE app DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE TABLE users (...) DEFAULT CHARSETutf8mb4;同时检查连接字符集。SHOW VARIABLES LIKE character_set%;会看到客户端连接相关的多个变量常见坑是查询出来character_set_client和character_set_results不一致导致写入时被转换、读取时又被转乱。命令行会话用SET NAMES utf8mb4;一步统一三个变量JDBC连接串里加characterEncodingutf8解决程序侧乱码。排序规则上utf8mb4_unicode_ci按Unicode排序更准utf8mb4_general_ci性能略好但个别字符排序不标准8.0新增utf8mb4_0900_ai_ci支持重音不敏感。选哪个不重要重要的是同一张表内不要混用不同collation否则JOIN时索引可能失效。5.2 隐式类型转换索引失效易漏点WHERE phone 13800138000其中phone定义为char(11)MySQL却全表扫了。为什么漏多数人以为MySQL会把数字自动转成字符串比较实际上MySQL会自动把字符串列类型隐式转为数字再比较这个转换等于在索引列上做了函数运算破坏了B树的有序查找。在数据量小时感觉不到几张百万行的用户表一跑慢查询立刻暴露。怎么补让比较字面量和列类型一致写成WHERE phone 13800138000。两张表关联时也要注意字段类型和字符集一个utf8mb4的varchar列和一个latin1的varchar列做JOIN优化器会先把其中一列转为utf8mb4再比较转换发生在被驱动表上索引同样失效。发现手段很简单EXPLAIN后看key是否为空再用SHOW WARNINGS查看优化器提示里面常出现“Implicit conversion”字样。用CAST显式表达意图能避免歧义WHERE phone CAST(13800138000 AS CHAR)但既然能写字符串直接改字面量更自然。复习时把隐式转换和函数运算放在同一类因为它们触发同一套失效逻辑。5.3 NULL与空字符串的区别易漏点COUNT(col)的结果比自己预期小一截WHERE name ! 漏掉了name为NULL的记录唯一索引允许插入多行name为NULL。为什么漏SQL的NULL表示“未知”不是“空值”。空字符串是一个确定的值而未知值不参与等值比较、不等于任何东西。很多从编程语言过来的人习惯把NULL当“空串”处理结果在统计和过滤上不断翻车。怎么补设计表时优先NOT NULL DEFAULT 让空状态用空字符串表达从源头减少NULL分支。统计时用COUNT()取代COUNT(col)COUNT()统计所有行COUNT(col)只统计该列不为NULL的行两者语义不同。判断用IS NULL / IS NOT NULL不要写 NULL或! NULL这类比较的结果永远是NULL过滤器会把它当假。进阶知识点有两个唯一索引里MySQL允许存在多个NULL值因为NULL不与任何值相等GROUP BY会把所有NULL值分成一组ORDER BY ASC时NULL默认排在最前面想排到后面要写ORDER BY col IS NULL, col。这些知识点分开看不难但放在一张真实表里同时出现时最容易让人摸不着头脑。5.4 分页深翻页问题易漏点LIMIT 200000,10测试时正常一上线就拖垮数据库。为什么漏LIMIT offset,count先读offsetcount行再丢掉offset行数据量小时几百毫秒数据量到千万级光扫描和丢弃就吃掉大量IO。小规模环境很难复现所以很多学习资料只在优化章节提一句实战时才成为血泪教训。怎么补优先把翻页改成基于游标的写法-- 传统写法深翻页慢 SELECT * FROM orders ORDER BY id LIMIT 200000, 10; -- 延迟关联先索引取id再回表取整行 SELECT o.* FROM orders o JOIN (SELECT id FROM orders ORDER BY id LIMIT 200000, 10) tmp ON o.id tmp.id; -- 游标写法依赖上一页最后一条id SELECT * FROM orders WHERE id 200000 ORDER BY id LIMIT 10;第一种写法会让扫描行数等于offset10第二种写法先走二级索引只取id再拿这10个id回表回表次数只有10次第三种写法利用主键有序性直接跳过前20万行是最快的。参数说明游标写法要求排序字段唯一如果按create_time排序而create_time有大量重复值要写成ORDER BY create_time, id同时WHERE条件带上(create_time, id)的比较。像社交产品那种“加载更多”场景天然适合游标分页需要“跳转到第N页”的网页端则适合延迟关联。复习时把三种写法写一遍深翻页就再也不是玄学。5.5 主从复制中的binlog格式易漏点主库执行了一条含有不确定函数的UPDATE从库重放后两边数据对不上。为什么漏单机学习完全看不到binlog也不会开从库等高可用方案真正落地时才发现statement格式的坑。statement格式记录的是SQL原文从库按同样的SQL执行一遍如果SQL里用了NOW()、UUID()主库和从库分别执行一次时间或随机值未必相同数据理所当然不一致。怎么补生产环境显式设置binlog_formatROW。row格式记录的是每一行变更前和变更后的值从库直接应用结果不依赖SQL语义最安全代价是日志量变大。可以用mysqlbinlog查看row格式的可读输出mysqlbinlog --base64-outputdecode-rows -vv /var/lib/mysql/mysql-bin.000001看到的是类似“### UPDATEdb.table”的逐行数据而不是SQL原文。配置上binlog_format是动态变量可以SET GLOBAL修改但建议写入my.cnf的[mysqld]段并在低峰期重启避免旧事务混用两种格式。如果担心日志膨胀把binlog_row_image设为minimal只记录变更的列同时把sync_binlog和innodb_flush_log_at_trx_commit都设为1做到事务提交与binlog落盘同步这是主从不丢数据的基础配置代价是每个事务多几次fsync。复习时不需要背所有组合只需要能说出“statement不安全、row安全但体积大用binlog_row_image控制体积”就够了。6. 复习清单从查漏补缺到自测闭环复习到最后最怕的是“看了十几章合上书什么都想不起来”。我的做法是拿复习清单做三轮自检。第一轮合上资料在白纸上默写知识地图自底向上写存储引擎、索引、事务与锁、优化、主从复制每层只写三个关键词。第二轮对照下面的自测问题表答不出来的先划线再回到对应章节看一遍。第三轮把每条上机跑一遍无法当场写对的都算盲区。模块自测问题答不上来先做什么SQL基础能否按顺序说出DQL执行顺序找5条SQL标注每阶段数据量存储引擎InnoDB和MyISAM的索引组织差异造两张等量表对比查询计划索引最左前缀、回表、覆盖索引能否讲清手建联合索引跑EXPLAIN观察key_len事务与锁RR为什么能消除常见幻读画read view和间隙锁两张图性能优化EXPLAIN的type和Extra代表什么造百万行表复现filesort和temporary易错点隐式转换、NULL、深翻页如何避免逐个跑EXPLAIN并记录type变化这三轮做完才算把知识变成可调用的工具。具体做法上我习惯把自测问题做成一张小卡片贴在资料对应章节的扉页复习时不翻正文先看问题能不能自己答出来答不出的才是真正需要补的。这份MySQL学习资料本身按同样的体系组织拿着这份清单去对照章节效率会高很多。从那以后我每次学完一个模块都强制走一遍“默写地图→回答自测问题→上机复现”的循环再也不敢跳过EXPLAIN直接改SQL。遇到模棱两可的概念先给旁边的同学讲一遍讲不通的地方就是下一次复习的入口。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?