这套100道MySQL SQL练习题,是我带新人入行数据库时反复打磨出来的一套训练材料。说句实话,SQL这项技能,看再多的教程都不如亲手写几十条查询来得实在。100道题做完,你对MySQL日常开发中最常用的那些操作,基本就形成了肌肉记忆,面试笔试碰上基础题目也能从容应对。
这套题不追求偏难怪,定位就是基础入门,覆盖从最简单的SELECT查询开始,一直到多表JOIN、子查询、聚合分组、窗口函数这些开发中高频使用的语法。适合三类人:刚接触数据库的初学者、准备数据库岗位面试但基础不牢的求职者、想系统复习一遍SQL核心语法的开发者。下面我把这套百题的设计思路、知识分布、典型题解和刷题方法完整拆开讲一遍。
1. 为什么是100道题:这套练习的设计逻辑
1.1 基础题的核心训练目标
说到SQL练习,很多人有个误区,觉得随便找几道题做做、会写基本查询就够了。实际上,SQL的学习曲线是典型的“上手容易精通难”,几条简单的SELECT谁都会写,但一旦涉及多表关联、分组过滤、子查询嵌套这些组合操作,绝大多数人就开始犯迷糊。
100道基础题的核心训练目标是三件事:第一,把语法记牢,让你不用翻文档也能写出结构完整的查询语句;第二,建立数据处理的直觉,看到一句业务需求描述,脑子里能立刻反应出用哪类SQL操作去实现;第三,养成执行顺序的思维习惯,知道SQL的书写顺序和执行顺序并不一致,这对后面理解优化器行为、排查慢查询至关重要。
有人在知乎上问过一个问题:SQL基础到底指什么?我的看法是,基础不是“你会SELECT FROM WHERE”就算过关,而是你能流畅地处理条件过滤、排序去重、聚合统计、多表关联、子查询这五类核心操作,并且能把这些操作组合起来解决实际的数据提取需求。这套100题就是按照这个标准来设计的。
1.2 百题覆盖的知识域分布
在设计题目分布时,我参考了大量实际开发中的查询需求,发现日常业务中80%以上的SQL操作都集中在几个核心场景。为了让练习有针对性,100道题按照知识点分布如下:
| 知识模块 | 题量范围 | 考察重点 |
|---|---|---|
| 基础查询与条件过滤 | 约25题 | SELECT、WHERE、运算符、LIKE模糊匹配 |
| 排序、分页与去重 | 约15题 | ORDER BY、LIMIT、DISTINCT |
| 聚合函数与分组统计 | 约20题 | COUNT、SUM、AVG、MAX、MIN、GROUP BY、HAVING |
| 多表连接 | 约15题 | INNER JOIN、LEFT JOIN、RIGHT JOIN、自连接 |
| 子查询 | 约15题 | 标量子查询、IN子查询、EXISTS子查询 |
| 窗口函数与其他进阶函数 | 约10题 | ROW_NUMBER、RANK、CASE WHEN、日期函数 |
题目排序不是随机的,而是遵循从简单到复杂的梯度逻辑。前25题只需要一张表就能解决,培养最基本的语法手感;中间的题目引入多表和分组,开始考验逻辑能力;最后10题加入窗口函数和CASE WHEN,为衔接真实业务需求做过渡。这样排下来,每道题都不是孤立的,前后之间存在螺旋上升的关系。
1.3 学习节奏与心态建议
100道题听起来不少,但如果按照合理的节奏推进,一周左右就能完成第一轮。我的建议是每天15到20题,每道题先自己写,写不出来再看答案,看完答案一定要动手执行一遍,然后在自己的笔记里记下这道题考察的知识点和犯错原因。
基础阶段最容易犯的一个毛病是眼高手低。看着答案觉得“这我会”,但实际上手一敲,不是这里少了逗号,就是GROUP BY和聚合函数的搭配有问题。我见过程序员笔试里栽在“查询每个班级人数大于5人的班级”这种简单题目上的,不甘心也没用,平时写得少就是会卡壳。所以这套题的目的从来不是“看过”,而是“写过”。
2. 刷题前的地基:建库建表与环境准备
2.1 一套经典的学生课程成绩表结构
100道基础练习题,需要一个统一的数据环境来支撑。我建议所有练习都基于同一套经典的“学生-课程-成绩”三表结构,这套结构在真实场景中极其常见,而且覆盖了练习所需的全部关联场景。
三张表的字段设计如下:
学生表 student:
| 字段名 | 类型 | 说明 |
|---|---|---|
| s_id | INT | 学号,主键 |
| s_name | VARCHAR(50) | 姓名 |
| s_gender | CHAR(2) | 性别 |
| s_age | INT | 年龄 |
| s_class | VARCHAR(20) | 班级 |
课程表 course:
| 字段名 | 类型 | 说明 |
|---|---|---|
| c_id | INT | 课程号,主键 |
| c_name | VARCHAR(50) | 课程名 |
| c_teacher | VARCHAR(20) | 授课教师 |
选课成绩表 score:
| 字段名 | 类型 | 说明 |
|---|---|---|
| s_id | INT | 学号,联合主键之一 |
| c_id | INT | 课程号,联合主键之一 |
| score | DECIMAL(5,2) | 成绩 |
选择这三张表有讲究。体量小,每张表十来个字段、二三十条记录就够用,查询结果一眼能看出对错;关系明确,学生和课程之间是多对多的选课关系,正好用来练习各种JOIN场景;字段类型丰富,有字符串、数字、日期类字段可以全方位覆盖函数练习。
2.2 MySQL环境配置与初始化数据
在动手做题之前,你需要先准备一个能跑的MySQL环境。安装版本我建议选择MySQL 5.7或8.0,两个版本在基础SQL语法上几乎没有差别,练习过程中遇到的具体问题我再在后文单列一节来聊。
启动MySQL服务后,第一步是创建练习库。按如下方式操作:
CREATE DATABASE IF NOT EXISTS sql_practice DEFAULT CHARACTER SET utf8mb4; USE sql_practice;然后创建三张表:
CREATE TABLE student ( s_id INT PRIMARY KEY, s_name VARCHAR(50), s_gender CHAR(2), s_age INT, s_class VARCHAR(20) ); CREATE TABLE course ( c_id INT PRIMARY KEY, c_name VARCHAR(50), c_teacher VARCHAR(20) ); CREATE TABLE score ( s_id INT, c_id INT, score DECIMAL(5,2), PRIMARY KEY (s_id, c_id) );建好表之后,插入练习数据。这里有一个实操细节:学生表和课程表的记录数不要太少,我建议学生表30条、课程表10条、成绩表80条左右,这样在做JOIN和GROUP BY练习时,结果才具备足够的区分度。数据内容随你设计,但要注意包含一些边界情况,比如存在没有选课的学生、存在年龄相同的同学、存在成绩为空的情况,这些边界数据是后面很多易错题的关键。
2.3 练习工具的选择建议
环境就绪后,还需要选一个合适的查询工具。命令行mysql客户端是最轻量的选择,打开终端输入密码就能开干,但缺点是没有表格化显示,多列结果一混容易看花眼。
我更推荐使用图形化客户端,比如Navicat、MySQL Workbench或者开源免费的DBeaver。这些工具支持选中一段SQL只执行选中部分,还能把查询结果按表格形式展示,做练习题时对答案、看结果都很直观。特别是当你需要反复调试一条复杂查询时,图形化工具的体验远好于命令行。
实际操作中我的习惯是开两个窗口:一个窗口放题目列表,另一个窗口用客户端连接数据库执行语句。每做完一道题,在题目列表上打勾标注,顺便写上这道题的关键语法点。看似是笨办法,但200题刷下来,这份标注就是你最个性化的SQL笔记。
3. 核心知识点拆解与典型题目解析
3.1 基础查询与条件过滤
基础查询是整个SQL学习的起点,这部分题目大约占25题,覆盖SELECT语法、DISTINCT去重、WHERE条件过滤、运算符优先级和LIKE模糊匹配。
最基本的查询写法是:
-- 查询所有学生的所有字段 SELECT * FROM student; -- 查询指定字段并起别名 SELECT s_id AS 学号, s_name AS 姓名 FROM student;条件过滤部分要特别注意运算符的优先级问题。AND的优先级高于OR,这是几乎所有SQL初学者的第一个坑。举个例子,查询“年龄大于20岁或者是女生且班级为一班”的学生,如果写成下面这样:
SELECT * FROM student WHERE s_age > 20 OR s_gender = '女' AND s_class = '一班';执行结果会和你预期的完全不同。因为AND先执行,条件实际变成了“年龄大于20岁 或者 (女生且一班)”。正确的写法是加括号明确优先级:
SELECT * FROM student WHERE (s_age > 20 OR s_gender = '女') AND s_class = '一班';这一点在100道题里我至少埋了三四道类似的陷阱题,目的就是让你养成“复杂条件必加括号”的习惯。还有一个高频考点是LIKE模糊匹配中通配符的使用,%代表任意多个字符,_代表任意单个字符。这个规则看着简单,但一旦出现LIKE '%a%b%'这种多个通配符叠加的情况,很多人就开始晕。踏踏实实写几道题,比背十遍通配符规则都有效。
3.2 排序、分页与去重
排序和分页是业务系统中最高频的操作之一,这类题目大约15道。
排序的核心语法是ORDER BY,默认升序ASC,降序用DESC。可以按照一个字段排序,也可以按多个字段进行组合排序。组合排序的逻辑容易出错的地方在于:排序优先级从左到右,前面的字段优先。例如:
-- 先按班级升序排列,班级相同再按成绩降序排列 SELECT * FROM student ORDER BY s_class ASC, s_score DESC;分页查询在MySQL中使用LIMIT子句,格式是LIMIT offset, row_count,其中offset表示跳过多少条记录,row_count表示取多少条。初学者最常见的错误是把LIMIT 10, 20理解成“取第10条到第20条”,实际上它的含义是“跳过前面10条,从第11条开始取20条”。这个理解直接关系到分页公式:
-- 每页显示10条,查询第3页的数据,offset = (页码-1) * 每页条数 SELECT * FROM student ORDER BY s_id LIMIT 20, 10;去重处理上,DISTINCT是最基础的方案,但很多初学者会把DISTINCT和多字段混在一起用错。DISTINCT作用于后面所有字段的组合,而不是单独某一列。我想查询所有班级列表,SELECT DISTINCT s_name, s_class的结果是名字和班级的组合去重,而不是只对班级去重。如果你想得到“有哪些班级”这个结果,应该写成:
SELECT DISTINCT s_class FROM student;这个细微差别在题目里专门设置了一道对比题,做完之后基本就能理解DISTINCT的行为特性了。
3.3 聚合函数与分组统计
这一部分是SQL基础中的重头戏,大约20道题,也是笔试面试中翻车率最高的部分。
聚合函数解决的是“统计”类需求,常用的有COUNT计数、SUM求和、AVG平均值、MAX最大值、MIN最小值。使用时有几个细节值得注意:COUNT(*)统计行数,而COUNT(具体列名)统计该列非空值的数量,两者在有NULL值的情况下结果不同;SUM和AVG会自动忽略NULL值,这在计算平均成绩时需要特别注意,如果没有选修某门课的学生成绩为NULL,AVG统计结果的分子分母和你预期的是否一致,要仔细想清楚。
GROUP BY是聚合函数的使用前提,它负责把数据按某个维度分组,然后组内聚合。这里有一条非常重要的规则:SELECT中出现的普通字段,必须包含在GROUP BY中。我来举个例子,查询每个班级的平均年龄:
SELECT s_class, AVG(s_age) AS avg_age FROM student GROUP BY s_class;这个写法是正确的,因为s_class在GROUP BY中。但如果在SELECT中加上s_name,就会报错或得到不确定的结果,因为同一班级里有多名学生,数据库不知道选择哪一个。
HAVING和WHERE是一对容易被混淆的兄弟。WHERE是在分组之前过滤原始记录,HAVING是在分组之后过滤聚合结果。两者的过滤时机完全不同,甚至可以在一条语句里同时使用:
-- 查询平均成绩大于85分的班级,且只统计年龄大于18岁的学生 SELECT s_class, AVG(score) AS avg_score FROM student JOIN score ON student.s_id = score.s_id WHERE s_age > 18 GROUP BY s_class HAVING AVG(score) > 85;上面这条SQL是练习中最典型的分组统计综合题,建议在100道题中反复练习这类组合逻辑,它几乎涵盖了开发中用得最多的查询模式。
3.4 多表连接JOIN
多表连接是SQL练习的分水岭,过了这一关,才算是真正理解关系型数据库的查询逻辑。这部分大约占15题。
内连接INNER JOIN取两个表的交集,左连接LEFT JOIN保留左表的全部记录,右连接RIGHT JOIN保留右表的全部记录。很多人记不住三种连接的区别,我常用一个生活化的类比来解释:把两张表想象成两个朋友圈子,INNER JOIN只认识两边都认识的人,LEFT JOIN以左边圈子为主,右边没有匹配的人就留空,RIGHT JOIN反过来。
实际操作中,LEFT JOIN的使用频率最高,因为业务中经常需要“以A表为主,补上B表的信息”。典型的题目是查询所有学生的选课情况,包括没有选课的学生:
SELECT student.s_name, course.c_name, score.score FROM student LEFT JOIN score ON student.s_id = score.s_id LEFT JOIN course ON score.c_id = course.c_id;这条SQL的关键逻辑在于:先以student为主表左连接score,拿到每个学生的选课记录;再以结果为基础左连接course,补全课程名称。如果某个学生没有选课,score和course的字段都会显示为NULL,但这名学生的姓名依然会保留在结果中。
JOIN的连接条件也有讲究,开发中最常见的错误是把条件写在WHERE里而不是ON里。对于INNER JOIN,两种写法结果相同;但对于LEFT JOIN,把条件写在WHERE里,会在连接完成后过滤掉左表中未匹配的记录,相当于把左连接变成了内连接,这是极其隐蔽的坑。这套题里我安排了两道互相对照的题目,就是让学习者亲手体会一下这个差异。
3.5 子查询的进阶应用
子查询技巧性强,大约15道题。核心思路是用一条查询的结果作为另一条查询的输入,先内后外逐层推进。
标量子查询返回单个值,常用于WHERE条件中的比较。比如查询成绩高于平均分的学生:
SELECT s_name FROM student WHERE s_id IN ( SELECT s_id FROM score WHERE score > (SELECT AVG(score) FROM score) );外层查询的学生名单来自成绩高于总平均分的记录,内层的平均分子查询先计算出整体基准线。执行顺序上MySQL会先执行最内层的子查询,拿到平均分,再逐层向外计算。这道题看起来简单,但它同时包含了IN子查询、标量子查询和WHERE过滤三个知识点。
EXISTS子查询是另一种常用形式,适合判断“是否存在”的业务场景。比如查询没有选任何课程的学生:
SELECT s_name FROM student s WHERE NOT EXISTS ( SELECT 1 FROM score sc WHERE sc.s_id = s.s_id );注意这里子查询的SELECT后面写的不是*,而是常量1。因为EXISTS只关心子查询是否有返回行,不关心具体返回什么内容,写1比写*性能更好,语义上也更清晰。这是经验之谈,很多教程里不会特意强调这个细节。
子查询相关的题目难度差异很大,从简单的标量子查询到嵌套两三层、关联内外层的复杂查询都有。做题时的核心策略是先拆后合,一层一层分析,不要试图一口吃成胖子。
3.6 窗口函数与CASE WHEN
最后10道题加入了窗口函数和条件判断逻辑,这部分既是基础的延伸,也是实战的预热。
窗口函数和GROUP BY最大的区别是:GROUP BY会把多行聚合成一行,而窗口函数不会改变行数,而是在每一行旁边额外计算出一个聚合值。ROW_NUMBER()是最常用的窗口函数之一,比如查询每个班级中成绩排名第一的学生:
SELECT s_name, s_class, s_score FROM ( SELECT s_name, s_class, s_score, ROW_NUMBER() OVER (PARTITION BY s_class ORDER BY s_score DESC) AS rn FROM student ) t WHERE t.rn = 1;这里先用窗口函数按班级分区、按成绩降序编号,班级内成绩最高的人编号为1,外层查询再过滤编号为1的记录。注意子查询得到的派生表必须起一个别名,这里是t,这是MySQL的语法要求,漏掉会直接报错。
CASE WHEN是实现条件逻辑的重要工具,语法结构类似于编程语言中的if-else。实际开发中常用于对数据进行分箱归类,比如把成绩转换成等级:
SELECT s_name, CASE WHEN score >= 90 THEN '优秀' WHEN score >= 60 THEN '及格' ELSE '不及格' END AS grade FROM student JOIN score ON student.s_id = score.s_id;这道题体现了SQL不仅会查数,还能直接完成数据加工和分类。掌握CASE WHEN之后,你对SQL表达能力的理解会上一个台阶,很多原本需要拿到程序里处理的转换逻辑,在SQL查询阶段就能直接完成。
4. 100道题的正确刷法:节奏、方法与复盘
4.1 三遍刷题法
100道题第一遍顺着做下来,我建议不要卡太久。每道题给自己十分钟,做不出来就看答案、理解答案、抄一遍答案并执行出结果,标记为“不会”。第一遍的目标是建立知识地图,搞清楚全部100个考点长什么样。
第二遍重点只刷第一遍标记为“不会”和“做错”的题目。这一遍要求合上答案独立完成,如果还是卡壳,回到对应知识点章节重新温习,再来一次。第二遍会明显比第一遍轻松,因为SQL的语法结构就那么多,第一遍见过的题型会在第二遍反复激活记忆。
第三遍属于考前冲刺或上岗前的快速回顾,这时候不看题目列表,而是只看知识点目录,尝试自己复述每一类题目的典型写法和注意事项。能复述出来,才是真正的掌握。
我见过不少学习者刷题只刷第一遍,做完就丢到脑后,结果半月之后SQL忘得精光。原因很简单:第一遍是输入,第二遍是输出,第三遍是内化,缺一步都不行。
4.2 刷题过程中的易错点速查
我把练习过程中学员踩过最多的坑整理成了一张表,你刷题时如果遇到类似报错或结果不对,优先检查这几类问题:
| 易错点 | 错误示例 | 正确做法 |
|---|---|---|
| WHERE后使用聚合函数 | WHERE AVG(score) > 60 | 聚合函数放在HAVING中 |
| GROUP BY遗漏普通字段 | SELECT s_name, COUNT(*) GROUP BY s_class | SELECT中出现字段必须在GROUP BY中出现 |
| JOIN条件放错位置 | LEFT JOIN后WHERE右表字段非空 | 连接条件写ON,过滤条件写WHERE |
| 子查询忘记别名 | FROM (SELECT ...) 后补t | MySQL要求派生表必须有别名 |
| 分页参数理解错误 | LIMIT 20,10理解为20-10条 | 实际含义是跳过20条取10条 |
| 字符集导致中文乱码 | 数据库字符集为latin1 | 统一使用utf8mb4 |
实战中每一个坑背后都是一次真实的报错或结果异常。刷题时把错误记录下来比做对题更有价值,因为错误暴露了你思维里的盲区,而做对的题往往掩盖了不确定的猜测。
4.3 如何利用错题做知识串联
错题本不是把错误抄一遍就完事,而是要顺着错误去反向补全知识结构。我在带人时经常问一个问题:这道题为什么错?是语法层面不理解,还是逻辑层面没想清楚条件之间的组合关系?两种错误的处理方式完全不一样。
语法层面的错误,比如少了逗号、括号不匹配、关键字拼错,这类问题只要多写就能自然减少,属于熟练度问题。逻辑层面的错误,比如把WHERE和HAVING搞混、JOIN类型选错、子查询的关联条件写反,这类问题需要回到原理层面去理解SQL的执行顺序。
建议每做完一组题目,抽出十分钟,把这一组涉及的知识点写在一张纸上,用箭头标出它们之间的关系。比如GROUP BY连接HAVING,HAVING连接聚合函数,聚合函数连接WHERE与JOIN的执行顺序差异,画完之后你会发现自己对SQL的理解不再是零散的知识点堆积,而是一张可以随时调用的知识网络。
5. 练习环境中常见的问题与排查实录
5.1 连接与启动类问题
刷题过程中最让人沮丧的往往不是题目做不出,而是环境突然出问题。我见过太多初学者卡在MySQL安装这一步,还没开始写SQL就放弃了。
MySQL在Windows环境安装时,最常见的问题是安装完成后服务无法启动。排查思路很简单:先确认是否以管理员身份运行了命令,然后查看错误日志定位原因。另一个高发问题是用zip包解压版MySQL时,缺少my.ini配置文件导致服务启动失败。解压版必须手动创建配置文件并指定basedir和datadir两个路径参数,同时确保datadir目录存在且为空。
连接服务时报Access denied for user 'root'@'localhost'是另一个高频问题。初次安装的root用户密码如果忘了,可以暂时跳过权限验证启动服务,然后重置密码。具体操作不展开细说,但这条思路你要有印象,后文排查表里我再统一整理。
5.2 SQL语法与执行异常速查
练习过程中,SQL语句执行报错也是家常便饭。下面整理高频报错的含义和解决方向,刷题时遇到可以直接对照参考。
| 报错信息 | 原因分析 | 解决方案 |
|---|---|---|
| Unknown column xxx in where clause | 列名不存在或写错,注意大小写 | 核对表结构字段名,MySQL在Linux下字段名区分大小写 |
| You can't specify target table for update in FROM clause | 子查询直接引用了需要更新的表 | 将子查询结果包一层派生表再操作 |
| Every derived table must have its own alias | 派生表没有别名 | 在子查询括号后加一个表别名 |
| Incorrect parameter count in the call to native function | 聚合函数参数个数错误 | 检查函数语法和括号 |
| Data too long for column | 插入或更新的内容超长 | 检查字段长度定义与数据内容 |
| Lock wait timeout exceeded | 表被事务锁住 | 检查是否有未提交的事务,使用SHOW PROCESSLIST排查 |
还有一种非常隐蔽的情况:SQL执行成功但返回的结果为空。这时候不能慌,要逐层排查——先单独执行内层子查询看是否有数据,再检查JOIN条件是否正确,最后确认过滤条件是否与表字段类型匹配。排查SQL逻辑问题最有效的方式就是“拆”,一条复杂SQL拆成多个简单片段逐步执行,问题永远在最容易忽略的那个环节。
5.3 数据正确性校验技巧
做完一道题,怎么确认自己的答案是正确的结果?很多人只依赖对比参考答案,但参考答案如果多年未更新,在版本差异下可能也会出现不准确的情况。
我的建议是使用多种方式交叉验证。比如查询“每门课程的最高分”,你可以先用GROUP BY加MAX函数得到结果,然后单独对每一门课执行一条简单查询来验证最高分是否正确。两条路径的答案一致,基本可以确认结果无误。
对于涉及多表连接和子查询的复杂题目,还有一个实用技巧:手动挑选几条数据人工计算。比如查询每个班级的学生人数,你先看一眼student表中一班有多少条记录,再去对比SQL结果,十几秒就能完成校验。这种校验收缩了反馈时间,会极大提高刷题效率。
6. 一百题通关之后:SQL进阶路线图
6.1 练习题与真实业务的差距在哪里
100道基础题做完,你对SQL语法肯定有全面认识了,但距离实际开发还有一段路要走。最大的差距在于:练习题的数据是干净规整的,每张表都有清晰主键,字段类型定义明确,没有脏数据。真实业务环境里,一张订单表可能混合了多种状态值,一个用户名字段可能包含各种不可见字符和前后空格。
另外,真实业务中的表结构通常要复杂得多,动辄几十上百个字段,一条查询需求不但要考虑取数逻辑,还得考虑性能消耗。同样是查询一个用户的最近一笔订单,在100万行数据上跑和在100条练习数据上跑,体验是完全不同的。练习题教会你“怎么写对”,实际业务要求你“怎么写好”。
6.2 千万不能忽略的SQL编码安全意识
学会SQL之后,必须建立的第一条红线是防SQL注入。SQL注入是Web开发领域最常见的安全漏洞之一,核心成因是开发者把用户输入直接拼接进了SQL语句。比如一个登录功能如果写成字符串拼接SQL,恶意用户通过在输入框里构造特殊符号,就能改变原来SQL的执行逻辑。
防御手段并不复杂,核心就一条:所有涉及用户输入的SQL都用参数化查询,也就是预处理语句加占位符的方式。无论是使用MySQLi、PDO还是MyBatis等开发框架,都提供了成熟的参数绑定机制。刷题练习时我们写的都是静态SQL,但心里要清楚,真实项目里基本不允许动态拼接SQL字符串。
6.3 下一步值得投入的四个方向
100道题之后,如果还想继续精进,我建议按下面四个方向规划学习路径。
第一个方向是索引与性能优化。先学会用EXPLAIN查看执行计划,理解全表扫描和索引扫描的差异,然后尝试大表环境下优化带WHERE条件、ORDER BY和JOIN的查询。这是从“会写SQL”到“写好SQL”的关键一步。
第二个方向是事务与锁机制。理解ACID特性、四种隔离级别、乐观锁和悲观锁的应用场景。这个方向偏理论,但面试高频,开发中遇到并发数据一致性问题时也会直接用到。
第三个方向是存储过程与函数。虽然现在很多团队不推荐在数据库层写复杂业务逻辑,但存储过程对理解SQL能力边界、处理批量数据任务仍然有价值。
第四个方向是深入窗口函数与分析型SQL。窗口函数在处理排名、同环比、累计求和等业务需求时表现极强,掌握之后能让你的SQL水平在同事中明显拉开差距。
我个人在实际刷完这一百题又带着几批新人通关之后的体会是:SQL基础的牢固程度,决定了你后续学习所有数据库进阶知识的速度。窗口函数、执行计划、优化器行为,这些听起来高级的概念,本质上都是基础语法的组合应用。基础不牢的人看EXPLAIN输出只是看个热闹,索引该建在哪里全靠猜;基础扎实的人则能快速理解执行计划中每一步的数据处理逻辑,从而做出正确的优化决策。
最后再分享一个小技巧:刷题过程中把你写过的每一条SQL都收藏到一个专门的文件里,按知识点归类。这个文件不需要多漂亮,但它是你亲手写出来的SQL代码库,之后在项目开发里遇到类似的数据提取需求,直接在里面搜索参考,比自己重新琢磨效率高得多。所以,别犹豫,装好MySQL,建好表,从第一题开始吧。