简介《mysql数据库笔试题一.pdf》是一份面向初级数据库开发、运维及笔试备考者的MySQL基础知识自测资料围绕数据库系统核心概念、SQL语言、事务与数据完整性、并发控制、安全性与约束等高频考点整理适合面试前刷题和课堂复习使用。资源共1个PDF文件大小为252KB内容以选择题、填空题、简答题为主并附答案与解析覆盖建表改表删表、存储过程、触发器、事务提交与回滚、常见约束等实操理论。目前已超过570人学习页面结构紧凑可直接打印或按题号自测对于正在准备数据库岗位笔试或想快速梳理MySQL基础框架的读者可作为一份轻量、集中的知识点提纲。1. 一份 MySQL 笔试题凭什么能筛掉一半候选人我见过太多这样的场面简历上写着“精通 MySQL”笔试时出一道“查找每个部门薪资最高的员工”能一次写对的不到三成。不是 SQL 语法不会而是对 MySQL 的底层机制、边界条件、以及“题目到底在考什么”缺乏体感。这份mysql数据库笔试题一.pdf类型的题目集本质不是在考“会不会写 SELECT”而是在考你对索引、事务、锁、以及数据库设计取舍的理解深度。它适合三类人准备跳槽的 CRUD 工程师用来做能力自查带新人的小组长用来当培训摸底卷还有那些被“增删改查”麻痹了、想看看自己到底几斤几两的开发者。别把它当成背答案的八股把它当成一面镜子——接下来我按笔试里最常出现的考点一层层拆给你看。2. 增删改查的隐藏考点基础题里的区分度2.1 DELETE 和 TRUNCATE一道送分题多少人栽在“自增 ID”上笔试题里最经典的送分题之一删除表里所有数据用 DELETE 还是 TRUNCATE如果只是答“TRUNCATE 快”只能拿一半分。真正的区分度在后续问题——执行完之后自增 ID 会不会重置-- 准备一张测试表 CREATE TABLE t_user ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4; INSERT INTO t_user(name) VALUES (a),(b),(c); -- 情况一DELETE 清空 DELETE FROM t_user; INSERT INTO t_user(name) VALUES (d); -- 此时 d 的 id 4而不是 1 -- 情况二TRUNCATE 清空 TRUNCATE TABLE t_user; INSERT INTO t_user(name) VALUES (d); -- 此时 d 的 id 1自增计数被重置这段代码的逻辑说明DELETE是逐行删除InnoDB 不会重置AUTO_INCREMENT计数器TRUNCATE是重建表结构DDL 操作计数器会归零。参数与行为差异要注意三点一是TRUNCATE在 MySQL 8.0 里是隐式提交的无法回滚二是TRUNCATE过程中会持有表的排他锁并发环境下影响更大三是如果表被外键引用TRUNCATE会直接报错这时候只能用DELETE。笔试题如果改成“怎么让 DELETE 之后自增 ID 重置”答案是用ALTER TABLE t_user AUTO_INCREMENT 1;。另外还有个冷门问法DROP和TRUNCATE有什么区别DROP直接删除表结构TRUNCATE保留了表结构只清数据两者对磁盘空间的释放程度也不同。2.2 你写的 UPDATE 是不是“无差别攻击”笔试里有一类题是给一段 UPDATE让找问题。最常见的坑是把UPDATE的WHERE条件写错或漏掉导致全表被更新。但进阶考点不是这个而是“更新时列的顺序和赋值的可见性”。-- 经典陷阱题交换两列的值 UPDATE t_user SET age score, score age WHERE id 1; -- 问题age 和 score 是交换了还是都变成了原来的 score -- 正确答案交换成功。MySQL 的 UPDATE 是“读旧值写新值”逻辑说明MySQL 的 UPDATE 在单条语句内是“先读取整行的旧值再计算赋值”所以age score, score age中右边的age和score都是更新前的值不会出现“age 变新值后再赋给 score”的情况。这和某些编程语言里“顺序赋值”的语义不同也是笔试题常用来考“对 MySQL 执行模型理解”的点。另一个常见考点是UPDATE与JOIN的配合-- 需求把订单表里用户等级为 VIP 的订单标记为“高优” UPDATE t_order o JOIN t_user u ON o.user_id u.id SET o.priority 1 WHERE u.level VIP;参数说明这里用JOIN子句替代子查询MySQL 是允许先JOIN再SET的。需要注意WHERE条件里的u.level走的是t_user的索引o.user_id走的是t_order的索引如果两边都缺少索引这 SQL 会把两张表都全表扫一遍线上环境会直接拖垮库。2.3 INSERT 的几种花式写法与“默认值”的坑热词里频繁出现“mysql设置默认值为0”和“mysql数据库修改结构”笔试题特别喜欢拿默认值做文章。-- 建表时设置默认值 CREATE TABLE t_config ( id INT AUTO_INCREMENT PRIMARY KEY, retry_count INT NOT NULL DEFAULT 0, remark VARCHAR(100) DEFAULT NULL ); -- 插入时如果不指定 retry_count就会用 0 INSERT INTO t_config(remark) VALUES (第一次失败); -- 等价于 INSERT INTO t_config(retry_count, remark) VALUES (0, 第一次失败);这里的逻辑点有三层。第一层DEFAULT只在 INSERT 语句“没有提供该列”时生效如果提供了NULL而列是NOT NULL DEFAULT 0会直接报错。第二层TIMESTAMP类型的默认值在 MySQL 5.6 之后可以用DEFAULT CURRENT_TIMESTAMP但DATETIME要到 5.6.5 之后才支持版本边界是考点。第三层如果建表时没给默认值列又是NOT NULLINSERT 时不传该列在严格模式下会报错在非严格模式下会根据数据类型自动填0或空串——这个“隐式默认值”行为是区分你是否理解sql_mode的试金石。笔试题还常考批量插入的效率INSERT INTO t (a,b) VALUES (1,2),(3,4),(5,6);比单条逐行插入快因为减少了 SQL 解析次数和日志刷盘次数。如果数据量是几十万行常见做法是改max_allowed_packet参数默认 4MB 可能不够大批次插入。3. 排序、分组与索引笔试最密集的“八股”核心区3.1 ORDER BY 不止是 ORDER BY排序规则与字符集陷阱热词里有“mysql排序”这几乎是所有笔试题绕不开的必考点。基础问法是“升序降序怎么写”进阶问法是“中文字段排序为什么不是拼音顺序”。-- 按创建时间倒序 SELECT * FROM t_order ORDER BY created_at DESC; -- 按状态升序、创建时间倒序 SELECT * FROM t_order ORDER BY status ASC, created_at DESC; -- 中文按拼音排序需要指定排序规则 SELECT name FROM t_user ORDER BY CONVERT(name USING gbk) ASC; -- 或者在建表时指定排序规则为 utf8mb4_zh_0900_as_csMySQL 8.0逻辑说明ORDER BY的默认排序规则取决于列的COLLATION。utf8mb4_general_ci下中文是按 Unicode 编码点排序的不是拼音。热词里的“mysql排序”问题多半是想问这个——中文排序要么建表时指定支持拼音的排序规则要么在查询里CONVERT转成 GBK 按拼音编码排。还有两个必考边界NULL值在升序里排在最前在降序里排在最后ORDER BY后面可以跟数字表示第几列但这是一种可读性很差的“玄学”写法代码评审时建议直接打回。3.2 GROUP BY 与 HAVINGWHERE 和 HAVING 的执行顺序之争“每个部门的平均薪资”是笔试题的“Hello World”但加一个条件就变成了陷阱题——“只看平均薪资大于 5000 的部门”。-- 正确写法 SELECT dept_id, AVG(salary) AS avg_sal FROM t_emp GROUP BY dept_id HAVING avg_sal 5000; -- 错误写法把条件放在 WHERE 里做筛选语义不同 SELECT dept_id, AVG(salary) AS avg_sal FROM t_emp WHERE AVG(salary) 5000 -- 这一行会直接报错 GROUP BY dept_id;参数说明WHERE在分组前执行作用于“每一行原始数据”HAVING在分组后执行作用于“每一组聚合结果”。MySQL 会经历 FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY 这条逻辑链路笔试题只要考这个本质上在考你能不能讲清楚“过滤时机”。还有一层常见的问法GROUP BY后面的列不一定非要在SELECT里出现但SELECT出的非聚合列如果既不在GROUP BY里又不是聚合函数在 MySQL 的ONLY_FULL_GROUP_BY模式下会直接报错——这是 MySQL 5.7 之后默认开启的行为也是大量老项目从 5.6 升级时翻车的重灾区。3.3 索引为什么总考B 树、回表与最左前缀笔试题里索引的比例往往占 30% 以上。热词里“mysql的数据库连接池”“mysql锁的分类”都离不开索引。先说结论MySQL InnoDB 的索引底层是 B 树主键索引的叶子节点存“整行数据”二级索引的叶子节点存“主键值”。理解了这个很多题都不用背直接推。-- 联合索引示例 ALTER TABLE t_order ADD INDEX idx_user_status (user_id, status); -- 能命中索引的查询 SELECT * FROM t_order WHERE user_id 100; SELECT * FROM t_order WHERE user_id 100 AND status 1; -- 不能命中索引的查询 SELECT * FROM t_order WHERE status 1;逻辑说明联合索引(user_id, status)按照“最左前缀原则”工作。只要查询条件里包含联合索引的最左列就能走索引跳过了最左列索引就失效退化为全表扫描。这里有个“排序也能用索引”的考点SELECT * FROM t_order WHERE user_id 100 ORDER BY status是不需要额外排序的因为(user_id, status)索引本身已经让status在同一个user_id内是有序的这叫“索引覆盖排序”EXPLAIN 里Extra列没有Using filesort就说明用上了。另一个高频坑是“隐式类型转换”导致索引失效-- user_id 是 INT 类型但查询用了字符串 SELECT * FROM t_order WHERE user_id 100; -- 可能走索引 SELECT * FROM t_order WHERE user_id 100abc; -- 字符串转数字失败不一定是全表扫但效率变差 -- phone 是 VARCHAR 类型但查询用了数字 SELECT * FROM t_user WHERE phone 13800138000; -- 索引会失效全表扫描原因MySQL 对VARCHAR列和数字比较时会把列的值隐式转换为数字导致无法使用索引内的字符串前缀匹配。这类题如果出现在笔试题里标准答题话术是“如果列类型是 VARCHAR传入的参数必须带引号对索引列做函数运算也会让索引失效比如WHERE DATE(created_at) 2024-01-01应该改成WHERE created_at 2024-01-01 00:00:00 AND created_at 2024-01-02 00:00:00。”3.4 从 EXPLAIN 看一道题是不是“真会”Extra 列的暗号笔试题里偶尔会给出一个EXPLAIN输出让判断 SQL 写得合不合理。我一般会建议候选人至少盯住type列和Extra列。type值含义效率ALL全表扫描最差能避免就避免index全索引扫描比 ALL 好但仍会遍历索引树range索引范围扫描BETWEENIN好ref非唯一索引等值匹配好eq_ref主键或唯一索引等值匹配最多返回一行很好const主键等值匹配最优Extra列如果出现Using filesort说明排序没用上索引如果出现Using temporary说明分组或去重创建了临时表如果出现Using index说明是覆盖索引不需要回表。这几条记住了笔试的 EXPLAIN 读图题基本不丢分。4. 事务、锁与存储过程从“背概念”到“讲场景”4.1 四个隔离级别与三类读异常费曼式的记忆法MySQL 事务是笔试必考热词里的“mysql事务处理”直指这里。隔离级别一共有四个读未提交、读已提交、可重复读、串行化。MySQL InnoDB 默认是“可重复读”这也是大多数笔试题的默认语境。-- 查看当前隔离级别MySQL 8.0 SELECT transaction_isolation; -- 5.7 及以前用这个 SELECT tx_isolation; -- 会话级修改 SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED; -- 事务标准示例 START TRANSACTION; UPDATE t_account SET balance balance - 100 WHERE account_id 1; UPDATE t_account SET balance balance 100 WHERE account_id 2; COMMIT; -- 如果中途某一步失败则 ROLLBACK记忆方法隔离级别越严并发性能越差但数据一致性越强。三类读异常分别是脏读读到别人未提交的数据、不可重复读同一条记录前后两次读不一样因为有人提交了 UPDATE、幻读同一范围查询两次行数变了因为有人提交了 INSERT。读未提交不防任何异常读已提交防脏读可重复读防脏读和不可重复读但 InnoDB 通过间隙锁和 MVCC 在默认级别下顺带解决了大部分幻读串行化全防但并发直接退化成队列。4.2 锁的分类共享锁、排他锁、意向锁、间隙锁热词里“mysql锁的分类”是个常青话题笔试题通常考的是“写一段 SQL判断它加了什么锁”。你别死记硬背按需求推。基于主键的UPDATE加的是行级排他锁。基于非索引列的UPDATE由于无法定位到具体行InnoDB 会对所有匹配行加锁如果表很大还会升级为表锁不是 MySQL 自动升的是走了全表扫描导致逐行加锁效果接近表锁。SELECT默认不加锁但在REPEATABLE READ下普通的SELECT走的是 MVCC 快照读不会阻塞别人而SELECT ... FOR UPDATE和SELECT ... LOCK IN SHARE MODE走的是当前读会加排他锁和共享锁。-- 当前读悲观锁加锁示例 START TRANSACTION; SELECT * FROM t_stock WHERE sku_id 100 FOR UPDATE; -- 其他会话的 UPDATE t_stock SET stock stock - 1 WHERE sku_id 100 会阻塞住 -- 直到本事务 COMMIT 或 ROLLBACK间隙锁是笔试里最让新人懵的锁。它是 InnoDB 在可重复读级别下对“索引记录之间的空隙”加的锁目的是防止幻读。比如查WHERE id 10 AND id 20如果 10 和 20 之间没有记录InnoDB 也会对这段间隙加锁让别的事务无法插入 1119 的新记录。工厂里因为这个引发的“死锁血泪经验”非常多——两个事务各自持有不同间隙的锁再相互申请对方间隙里的锁直接死锁MySQL 检测到后会回滚其中一方。笔试题不会让你写死锁复现但会考“为什么插入一条不存在的记录会阻塞”答案就是间隙锁。4.3 死锁定位看SHOW ENGINE INNODB STATUS数据库死锁也是热词里高频出现的。笔试题一般不会让你现场查但会给你两个事务的 SQL让你判断会不会死锁。日常工作中我排查死锁靠的是 MySQL 的日志输出SHOW ENGINE INNODB STATUS\G重点看LATEST DETECTED DEADLOCK段落里面有事务一、事务二各自持有和等待的锁。常见的死锁场景是事务 A 先更新 id1 的行再更新 id2 的行事务 B 先更新 id2 的行再更新 id1 的行。只要两个事务交错执行就必然死锁。解决办法无非两条业务上统一“按相同顺序访问资源”或者把隔离级别降到读已提交以关闭间隙锁减少锁冲突面。笔试题如果问到“你怎么避免死锁”标准答题思路是“单一语句尽量原子化、事务尽量短、访问资源排序、合理使用索引避免全表扫描导致的大范围加锁”。4.4 存储过程笔试为什么还考这个老古董热词里有“mysql存储过程”。虽然DBA圈子普遍建议少用存储过程但笔试题还是爱考原因很简单——存储过程能测试一个候选人对“流程控制 异常处理 事务边界”的综合能力。-- 笔试题常见写一个存储过程插入订单并扣减库存失败则回滚 DELIMITER $$ CREATE PROCEDURE proc_create_order( IN p_user_id INT, IN p_sku_id INT, IN p_quantity INT ) BEGIN DECLARE EXIT HANDLER FOR SQLEXCEPTION BEGIN ROLLBACK; RESIGNAL; END; START TRANSACTION; INSERT INTO t_order(user_id, sku_id, quantity) VALUES (p_user_id, p_sku_id, p_quantity); UPDATE t_stock SET stock stock - p_quantity WHERE sku_id p_sku_id AND stock p_quantity; -- 如果影响行数为 0说明库存不足主动抛错 IF ROW_COUNT() 0 THEN SIGNAL SQLSTATE 45000 SET MESSAGE_TEXT 库存不足; END IF; COMMIT; END$$ DELIMITER ;逻辑与参数说明DELIMITER是为了让 MySQL 客户端把BEGIN...END整体当作一个语句提交DECLARE EXIT HANDLER FOR SQLEXCEPTION是声明一个异常处理器任何 SQL 报错都会触发ROLLBACKSIGNAL SQLSTATE 45000是主动抛出自定义错误45000是用户自定义错误专用状态码。笔试阅卷时有没有把“库存扣减”限制在stock p_quantity条件下、有没有在影响行数为 0 时主动报错往往就是区分“背过教材”和“真的处理过并发扣减”的分水岭。5. 笔试最容易翻车的五个细节避坑与排查5.1 索引失效的“玄学”写法现象一条 SQL 在测试环境 200ms上了生产跑了 20 秒。原因生产数据量一大索引没走全表扫描了。最常见的三类索引失效写法对索引列用了LIKE %关键词前置通配符对索引列做了函数运算或类型转换OR连接的条件里只有一部分列有索引。解决把LIKE %关键词改成全文索引或LIKE 关键词%函数运算改成范围条件OR改写成UNION ALL或者确保OR两边都走索引。笔试题如果给了执行计划记得优先看possible_keys和key列——possible_keys非空但key为空说明优化器判断走索引还不如全表扫这种情况要检查数据分布和是否需要ANALYZE TABLE更新统计信息。5.2 等值查询查不到数据表里明明有字符集与排序规则现象SELECT * FROM t_user WHERE name Tom查不出数据但SELECT * FROM t_user WHERE name Tom 带空格能查出。原因是列的排序规则是utf8mb4_bin区分大小写和末尾空格另一个常见原因是表是utf8mb4但连接字符集是latin1参数传递时发生了编码转换导致等值比较失败。解决统一客户端、连接、表三级字符集SET NAMES utf8mb4只是改了连接层表结构确认DEFAULT CHARSETutf8mb4。笔试题遇到“中文乱码”“等值查询失败”先往字符集上想大概率能踩中考点。5.3 分页查询越翻越慢OFFSET 的代价被忽略了现象LIMIT 100000, 20这一页要好几秒。原因MySQL 的LIMIT offset, count需要先扫到 offset 那个位置再把后续 count 行返回——offset 越大扫描的“路过数据”越多。解决不要跳页深翻或者用延迟关联技巧-- 常见做法先只取主键再回表拿整行 SELECT t.* FROM t_order t JOIN ( SELECT id FROM t_order ORDER BY created_at DESC LIMIT 100000, 20 ) tmp ON t.id tmp.id;逻辑说明子查询只查idInnoDB 在二级索引上做覆盖扫描回表只发生在最终 20 行上比直接扫 100020 行再回表快一个数量级。如果你在笔试题里写上这一层加分是稳的。5.4 MySQL 5.7 与 8.0 的行为差异现象同一套表结构脚本5.7 能跑8.0 报错。最常见差异是8.0 移除了PASSWORD()函数、sql_mode默认更严格、自增主键被持久化重启后不会再复用旧值、utf8mb4成为默认字符集。热词里“mysql 5.7.44 安装过程”“linux mysql 8.0.44”这类搜索本身就说明很多人还在被版本差异折磨。解决笔试题如果写“请解释 MySQL 8.0 和 5.7 的区别”从默认隔离级别、窗口函数8.0 支持、CTE 通用表表达式、utf8mb4默认、caching_sha2_password认证插件入手。MySQL 8.0 默认的认证插件导致老客户端连不上是超高频踩坑点笔试题也爱出——答案是“安装mysql_native_password插件兼容旧驱动或者让客户端升级驱动”。5.5 连接池配置不当数据库“假死”的元凶现象应用报Connection pool exhausted数据库 CPU 不高但连接数被打满。原因连接池的最大连接数设置过大或者单条 SQL 执行过慢占住了连接。热词里“mysql的数据库连接池”反复出现说明这是真实痛点。解决连接池大小不是越大越好常见经验值是CPU 核心数 x 2 有效磁盘数。比如 8 核机器连接池 20 左右足够把连接池的最大等待时间maxWait设得短一点让请求快速失败而不是排队占死连接。如果笔试题问“数据库连接池参数怎么调”你把这个公式抛出来面试官就知道你踩过坑。6. 把笔试变成能力清单一道统计题的五种解法最后一章不聊虚的给你一个我平时自查用的标准动作拿一道面试必考题——“查询每个部门薪资最高的员工”逼自己写出五种解法每写一种就想清楚它的适用场景和性能边界。这道题就像一面照妖镜能照出你对窗口函数、关联子查询、JOIN、临时表、以及 MySQL 优化器的真实理解。-- 写法一关联子查询最直观但大数据量下性能差 SELECT e.* FROM t_emp e WHERE e.salary ( SELECT MAX(salary) FROM t_emp m WHERE m.dept_id e.dept_id ); -- 写法二JOIN GROUP BY先求最高薪再关联回原表 SELECT e.* FROM t_emp e JOIN ( SELECT dept_id, MAX(salary) AS max_sal FROM t_emp GROUP BY dept_id ) tmp ON e.dept_id tmp.dept_id AND e.salary tmp.max_sal; -- 写法三窗口函数MySQL 8.0 标准答案 SELECT * FROM ( SELECT e.*, ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC) AS rn FROM t_emp e ) tmp WHERE rn 1; -- 写法四临时表 自连接笔试题里偶尔能见到但不推荐 -- 写法五用 EXISTS 巧妙改变“最高”的语义返回并列第一的所有人 SELECT e.* FROM t_emp e WHERE NOT EXISTS ( SELECT 1 FROM t_emp m WHERE m.dept_id e.dept_id AND m.salary e.salary );参数说明与场景差异写法一的关联子查询每扫一行都要执行一次内层查询部门多、数据量大时性能会“翻车”但逻辑最容易讲清楚写法二先聚合再关联走了临时表在 MySQL 5.7 下比较稳写法三用ROW_NUMBER()在 MySQL 8.0 里是标准答案天然支持“每个部门只取一个人”的语义且可以扩展出RANK()和DENSE_RANK()来返回并列名次写法五“不存在比我更高的”在语义上等价于“等于最高薪”能保留并列的人适合业务上需要并列第一的场景。验证方法也很简单建一个 50 万行的表分别跑这五种写法看EXPLAIN里的type、rows和Extra你就能直观建立“SQL 写法和执行计划”之间的对应关系。我个人的习惯是每掌握一个新函数或新特性就找几道刷过的基础题用新写法重做一遍——比如窗口函数光看文档你记不住PARTITION BY和ORDER BY谁先谁后写一道题自己验证胜过背十遍语法。这个方向值不值得投入我的结论是MySQL 笔试的重点从来不是“背出答案”而是你能不能把一道基础题展开成对执行计划、索引结构、事务机制的完整推演。你愿意花一个周末把上述五个细节和五种解法亲手跑一遍比刷 200 道题更有用。这也是我这些年带新人时最常用的一份自查清单希望帮到你。本文还有配套的精品资源点击获取