2026/10/20 22:25:05

MySQL常用操作语句全梳理:从建库建表到增删改查

MySQL常用操作语句全梳理:从建库建表到增删改查 做了这么多年数据相关工作MySQL 始终是绕不开的那个基础工具。新手问我的第一句话往往是MySQL 简单操作语句到底怎么学老手偶尔也会回来翻翻常用语法这东西就像厨师的刀工看似基础但每天都要用用得好不好直接决定效率。这篇我就把平时最常碰到的 MySQL 操作语句从头到尾梳理一遍从连接数据库到建库建表从增删改查到条件过滤、分组排序再到实际排错的经验尽量讲透让刚入门的朋友能照着操作让有经验的朋友也能查漏补缺。MySQL 的学习曲线其实并不陡难点不在语法本身而在于很多人不知道每条语句背后的执行逻辑和使用场景。比如同样是查询什么时候用 WHERE什么时候用 HAVING为什么 DELETE 不加条件会闯祸这些只有在实操中踩过坑才会真正理解。这篇文章我会把常用语句的写法、参数选择的原因、以及隐藏的坑都一并讲清楚。1. 先搞明白 MySQL 操作到底在操作什么1.1 MySQL 的角色与核心概念MySQL 是一个关系型数据库管理系统本质上就是一个结构化的数据仓库。我们平时说的操作 MySQL其实是四层动作连接数据库服务本身操作数据库database相当于仓库里的大房间操作表table相当于房间里的货架操作数据行row相当于货架上的具体货物理解这四层关系特别重要。我遇到过不少朋友分不清删除数据库和删除表数据的区别一个命令下去把整个库都drop掉了半天的工作白费。底层逻辑其实很简单MySQL 服务端可以同时管理多个数据库每个数据库里有多张表每张表里有若干行数据。你操作的粒度不同语句不同风险等级也不同。这就像整理一间屋子你可以把整个房间空出来清空表数据也可以把整个房间拆了删除表还可以把整栋楼拆了删除数据库。三个操作看着相似破坏力完全不是一个级别。1.2 一个清晰的学习路径学习 MySQL 基础操作我建议遵循这条路径别跳步先掌握连接和退出知道怎么进入这个环境再学会查看已有内容比如 SHOW 系列语句然后练习建库建表这是所有操作的基础设施接着重点突破增删改查INSERT、SELECT、UPDATE、DELETE最后学习过滤、排序、分组这些进阶但常用的子句很多初学者上来就背语法背完就忘因为没有场景感。我自己的经验是拿一个真实的小需求练手比如做一个个人图书管理表不断往里面加数据、查数据、改数据比干背二十条语句有用得多。1.3 关键词与语句分类速览MySQL 的语句可以按功能分成几大类学习的时候心里有个谱DDL数据定义语言CREATE、ALTER、DROP、TRUNCATE操作的是结构DML数据操作语言INSERT、UPDATE、DELETE操作的是数据DQL数据查询语言SELECT最常用也最灵活DCL数据控制语言GRANT、REVOKE管理权限TCL事务控制语言COMMIT、ROLLBACK、SAVEPOINT保证数据一致性这篇文章重点覆盖 DDL 和 DML / DQL因为这些是日常操作中最常碰到的内容。权限和事务当然也重要但那是第二步的学习内容基础阶段先别贪多。2. 环境准备与连接数据库的实战细节2.1 安装与启停先有一个能跑的 MySQL工欲善其事必先利其器。学习 MySQL 操作的第一步是让服务跑起来。以最常见的 MySQL 8.x 版本为例无论你是用安装包还是用 Docker最终要确认的就是服务在监听 3306 端口。用 Docker 启动一个 MySQL 实例是最省事的方案几条命令就能拥有一个干净的测试环境。我之前在本地就是这么干的避免了安装包带来的各种系统服务冲突问题。典型的启动命令长这样docker run --name mysql-test \ -e MYSQL_ROOT_PASSWORDyour_password \ -p 3306:3306 \ -d mysql:8.0这里有几个关键点需要解释一下MYSQL_ROOT_PASSWORD环境变量是初始化 root 用户的密码第一次启动时必须设置-p 3306:3306把容器内的 3306 端口映射到本机这样本地客户端才能连接-d表示后台运行终端不会卡住如果你用的是传统安装方式装完之后在终端执行mysql --version能看到版本号就说明客户端没问题。再执行systemctl status mysqlLinux或者到服务管理器里查看 MySQL 服务是否启动Windows确认服务在线。提示测试环境建议关闭 MySQL 的密码强度校验插件否则设置简单密码会很费劲。首次初始化时可以加--validate-passwordOFF参数或者安装后再修改相关配置。2.2 命令行连接与图形工具的选择环境就绪后进入 MySQL 的命令行环境是第一步实操。基础命令格式是mysql -h 127.0.0.1 -P 3306 -u root -p参数含义-h指定主机地址本机测试用 127.0.0.1 就行-P指定端口默认是 3306大写 P 避免和密码参数混淆-u指定用户名管理员一般用 root-p表示需要输入密码注意小写 p输入密码后你会看到mysql提示符这就说明已经进入 MySQL 的交互终端了。在交互终端里有个很容易被忽略但非常实用的命令mysql SELECT VERSION(); ----------- | VERSION() | ----------- | 8.0.36 | ----------- 1 row in set (0.00 sec)这条语句可以快速确认服务版本排查问题时第一步就靠它。另外两个高频命令是-- 查看当前有哪些数据库 SHOW DATABASES; -- 切换使用某个数据库 USE database_name; -- 查看当前所在的数据库 SELECT DATABASE();USE这个命令特别重要因为后续所有表操作都得先确定在哪个数据库下进行。如果不切库直接查表MySQL 会报No database selected的错误。图形工具方面我平时用的是 DBeaver 和 Navicat 这类工具。图形工具适合查看数据、编写复杂查询但我不建议新手完全依赖图形界面因为命令行能让你更清楚地看到 SQL 语句的执行过程而且排查问题时很多时候只有命令行可用比如服务器上没有任何图形环境。2.3 第一个完整操作流从登录到查看数据把上面的命令串起来一个完整的操作流程是这样的# 1. 登录 mysql -u root -p # 2. 输入密码后进入 mysql # 查看所有数据库 SHOW DATABASES; # 3. 创建自己的测试库 CREATE DATABASE demo; # 4. 切换进去 USE demo; # 5. 查看库里的表此时应该是空的 SHOW TABLES;这一步操作完成你就已经完成了一次完整的连接-建库-切库流程。很多初学者在这一步会卡住错在忘记在语句末尾加分号或者USE后面没有跟上数据库名。记住在 MySQL 命令行中分号是语句的结束标志不写分号按回车MySQL 会认为语句还没输入完会给你继续输入的机会。3. 建库建表地基打牢后面才稳3.1 数据库的创建、修改与删除数据库的创建语法特别简单但有几个参数值得讲究CREATE DATABASE IF NOT EXISTS demo DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;关键点拆解IF NOT EXISTS表示如果同名库已存在就跳过避免报错。这在脚本里特别有用反复执行不会中断DEFAULT CHARACTER SET utf8mb4指定默认字符集。utf8mb4 是 utf8 的超集能存 emoji 和更多生僻字强烈建议所有新库都用它COLLATE utf8mb4_general_ci指定排序规则。_ci结尾表示大小写不敏感_bin结尾表示二进制严格比较字符集的选择会影响数据存储和查询比较的行为。举个实际例子如果字符集不对存中文可能变成问号排序时大小写字母混在一起也会出现看起来不合理的顺序。所以在建库时花几秒钟写好字符集后面能省很多事。查看和修改数据库属性的语句-- 查看建库语句能看到当前库的字符集和排序规则 SHOW CREATE DATABASE demo; -- 修改库的默认字符集 ALTER DATABASE demo DEFAULT CHARACTER SET utf8mb4;删除数据库的操作要格外谨慎DROP DATABASE IF EXISTS demo;DROP是不可逆的库里的表和数据会一起消失。我见过有人把DROP DATABASE写成DELETE DATABASE执行时报语法错误才发现。在测试库上随便玩没关系在正式环境操作前一定要再三确认。3.2 表结构设计要点与字段类型选择建表是数据库设计的核心环节。语法框架是这样的CREATE TABLE IF NOT EXISTS books ( id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY, title VARCHAR(200) NOT NULL, author VARCHAR(100) DEFAULT 佚名, price DECIMAL(10, 2), stock INT NOT NULL DEFAULT 0, published_date DATE, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;这张表用来存图书信息字段选择本身就有讲究id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY自增主键每行数据的唯一标识。用UNSIGNED可以把负数浪费的空间省出来主键范围翻倍title VARCHAR(200) NOT NULL书名一般不超过 200 字符。NOT NULL保证每条记录都必须有书名防止脏数据author VARCHAR(100) DEFAULT 佚名作者允许为空但给了默认值方便插入时省略price DECIMAL(10, 2)价格用定点数而不是浮点数。10表示总位数2表示小数位这样算钱的时候不会出现浮点误差stock INT NOT NULL DEFAULT 0库存数量整数类型published_date DATE出版日期只用日期部分created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP记录创建时间自动生成不用手工插入对于字段类型我总结了几个原则数字就用 INT、BIGINT、DECIMAL别用 VARCHAR 存数字。有人为了省事把手机号存成 VARCHAR这倒可以因为手机号不参与计算但价格、数量这种要计算的字段必须用数值类型字符串定长就用 CHAR变长就用 VARCHAR。身份证号这类定长字段用 CHAR 性能更好标题描述这类用 VARCHAR 更省空间日期时间用 DATE、DATETIME、TIMESTAMP。DATETIME 范围更大TIMESTAMP 会自动更新如果设置了ON UPDATE CURRENT_TIMESTAMP大文本考虑 TEXT但尽量不要作为主要查询字段ENGINEInnoDB是存储引擎的选择。InnoDB 支持事务、行级锁、崩溃恢复是 MySQL 默认也是最可靠的引擎。除非你知道自己在做什么否则就用 InnoDB别碰 MyISAM。3.3 表结构的修改与查看业务变化了表结构也要跟着调整。最常用的 ALTER 语句如下-- 新增字段 ALTER TABLE books ADD COLUMN pages INT DEFAULT 0; -- 修改字段类型 ALTER TABLE books MODIFY COLUMN price DECIMAL(12, 2); -- 修改字段名保留类型 ALTER TABLE books CHANGE COLUMN author writer VARCHAR(100); -- 删除字段 ALTER TABLE books DROP COLUMN pages; -- 重命名表 ALTER TABLE books RENAME TO book_info; -- 或者 RENAME TABLE book_info TO books;查看表信息的常用语句-- 查看建表语句 SHOW CREATE TABLE books; -- 查看表结构简洁版 DESC books; -- 查看表结构详细版包含字段注释等信息 SHOW FULL COLUMNS FROM books;这里的DESC books;是我用得最多的命令在写任何 SQL 之前先看一眼表结构确认字段名有没有记错类型是什么避免写出来的语句一执行就报字段不存在。提示修改表结构时如果是在线业务要注意锁表问题。MySQL 8.0 里大部分 ALTER 操作已经做了优化但像MODIFY COLUMN这种类型变更如果数据量大依然可能消耗较长时间线上操作要避开高峰期。4. 增删改查绕不开的四大金刚4.1 INSERT 插入数据的多种姿势插入数据是最基础的动作。最简单的形式INSERT INTO books (title, author, price, stock, published_date) VALUES (深入浅出MySQL, 某开发者, 59.00, 100, 2024-01-15);这里的规范是字段列表和值列表要一一对应。如果你忽略字段列表直接写INSERT INTO books VALUES (NULL, SQL必知必会, 某作者, 49.00, 50, 2023-06-01, NOW());这种方式要求 VALUES 里的值必须按表结构的所有字段顺序排列少一个或多一个都不行。实际开发中我建议总是显式写字段列表因为表结构经常会变多字段的插入方式一旦字段顺序调整就废了显式字段列表更抗折腾。一次插入多行是提升效率的常用方式INSERT INTO books (title, author, price, stock) VALUES (MySQL实战, 张三, 69.00, 200), (数据库原理, 李四, 39.00, 150), (SQL优化技巧, 王五, 49.00, 80);这里有几个细节自增主键 id 不用写MySQL 会自动分配created_at有DEFAULT CURRENT_TIMESTAMP不用写也会自动填充author有默认值佚名如果不写就用默认值插入时最常遇到的错误就是Data too long for column。比如 title 字段是VARCHAR(200)你插入的书名超过 200 个字符就会报错。遇到这种问题要么缩短数据要么用 ALTER 把字段类型改大。还有个实用的小技巧用INSERT IGNORE可以忽略插入时的重复键错误INSERT IGNORE INTO books (id, title) VALUES (1, 旧书);如果 id 已经存在这条语句会静默跳过而不报错。而ON DUPLICATE KEY UPDATE则是存在就更新不存在就插入INSERT INTO books (id, title, stock) VALUES (1, 旧书, 10) ON DUPLICATE KEY UPDATE stock VALUES(stock);这个语法在做数据同步时非常香可以避免先查询再决定插入还是更新的代码逻辑。4.2 SELECT 查询从最简单到最常用查询是 MySQL 操作语句中使用频率最高的部分。最简单的全表查询SELECT * FROM books;这条语句会返回 books 表所有列、所有行的数据。适合小表快速看数据但线上环境数据量大时千万别用SELECT *因为会把不需要的字段也拉出来浪费 IO 和带宽。指定字段查询SELECT title, price FROM books;给字段起别名让结果显示更友好SELECT title AS 书名, price AS 价格 FROM books;这里的AS也可以省略写成SELECT title 书名, price 价格但加了 AS 更清晰而且某些场景下不加 AS 会产生歧义。去重查询用DISTINCTSELECT DISTINCT author FROM books;这条语句能列出所有不重复的作者名。注意DISTINCT是作用于整行所有字段的组合不是只作用于第一个字段。比如SELECT DISTINCT author, price FROM books是作者价格的组合去重。条件查询就是在后面加 WHERESELECT title, price FROM books WHERE price 50; -- 多条件组合 SELECT title, price FROM books WHERE price 50 AND stock 0; -- 或者关系 SELECT title, price FROM books WHERE author 张三 OR author 李四;这里要特别注意逻辑运算符的优先级AND 的优先级高于 OR。如果你写WHERE price 50 OR price 100 AND stock 0实际执行的是price 50OR (price 100 AND stock 0)。如果想表达价格小于 50 或大于 100并且库存大于 0必须加括号WHERE (price 50 OR price 100) AND stock 0这个坑我在早期写业务 SQL 时踩过查出来的数据数量完全不对排查了很久才发现是优先级问题。习惯性加括号是保平安的最好习惯。模糊查询用LIKESELECT title FROM books WHERE title LIKE %MySQL%;%匹配任意长度的字符包括零个字符_匹配单个字符LIKE %MySQL%表示标题中包含MySQL的书。要注意的是以%开头的 LIKE 查询无法使用普通索引数据量大时会全表扫描。如果前缀能确定写成LIKE MySQL%就能走索引。范围查询可以这样写SELECT title, price FROM books WHERE price BETWEEN 50 AND 100; SELECT title, published_date FROM books WHERE published_date IN (2024-01-01, 2024-06-01, 2024-12-31);BETWEEN是闭区间包含两头。IN后面跟一个列表等价于多个 OR 条件的简写。4.3 UPDATE 更新数据的正确姿势UPDATE 语法UPDATE books SET price 45.00 WHERE id 1;这条语句把 id 为 1 的书的价格改成 45.00。关键就是 WHERE 条件它决定哪些行会受影响。最常见的惨痛事故是忘写 WHEREUPDATE books SET price 45.00;这条语句会把所有书的价格都改成 45.00。如果没有备份事故现场简直惨不忍睹。MySQL 命令行默认为每条 UPDATE 都会显示受影响的行数看到数字不对还能及时反应过来。多字段一起更新UPDATE books SET price 55.00, stock 30 WHERE title SQL优化技巧;这里建议先用 SELECT 确认 WHERE 条件匹配的数据SELECT id, title, price FROM books WHERE title SQL优化技巧;确认无误再执行 UPDATE。这是我个人习惯也算是一个保命习惯。在测试环境无所谓在生产环境任何 UPDATE 和 DELETE 之前先跑一条同条件 SELECT成本极低收益极大。批量更新时可以用CASE WHEN来一次更新多条记录UPDATE books SET price CASE WHEN id 1 THEN 50 WHEN id 2 THEN 60 ELSE price END WHERE id IN (1, 2);这种方式比循环执行多次 UPDATE 效率高得多适合固定的映射关系更新。4.4 DELETE 删除数据清空还是删表删除数据的基础语法DELETE FROM books WHERE id 1;和 UPDATE 一样WHERE 条件就是生命线DELETE FROM books;这条语句会删除表中所有行但表结构还在。如果只是想清空数据、保留表结构有更高效的方式TRUNCATE TABLE books;DELETE 和 TRUNCATE 的区别值得说清楚对比项DELETETRUNCATE删除范围可带 WHERE删除指定行全部清空不支持 WHERE是否可回滚在事务中可回滚不可回滚自增ID继续递增从 1 重新开始执行速度逐行删除慢快速释放整个表的数据页锁范围行级锁表级锁刚才说了TRUNCATE 不可回滚而且会重置自增 ID。如果你只是想删掉全部数据但保留 ID 从 1 开始用 TRUNCATE如果你想精确控制删哪些行用 DELETE。我见过有人用 DELETE 清空几十万行的大表执行了大半天还没结束最后改用 TRUNCATE 几秒钟搞定。生产环境删除数据更大的隐患是删除后无法恢复。所以有个经验可以分享删除之前先备份。小表可以直接用 CREATE TABLE 备份CREATE TABLE books_bak_202401 AS SELECT * FROM books;或者直接用 mysqldump 工具导出。别嫌麻烦真出了问题就知道备份有多值钱。5. 查询进阶让数据乖乖听话5.1 WHERE 之外的常用过滤与排序查询不只是把数据拿出来更多时候是要按条件筛选、按规则排序。先把排序讲清楚SELECT title, price FROM books ORDER BY price ASC; -- 降序 SELECT title, price FROM books ORDER BY price DESC; -- 多字段排序 SELECT title, author, price FROM books ORDER BY author ASC, price DESC;ORDER BY的默认排序是升序ASC字段值相同时可以继续指定下一个排序字段。多字段排序的执行逻辑是先按第一个字段排第一个字段相同的再按第二个字段排。比如上面这条语句先按作者名的字母升序排同一个作者的书籍再按价格从高到低排。限制返回行数用 LIMITSELECT title, price FROM books ORDER BY price DESC LIMIT 10;这条语句返回价格最高的 10 本书。LIMIT 的偏移量用法SELECT title, price FROM books ORDER BY price DESC LIMIT 10, 20;这里的LIMIT 10, 20表示跳过前面 10 行从第 11 行开始取 20 行。注意第一个数字是偏移量第二个数字是行数别搞反了。分页查询时核心就是这两种写法-- 第1页每页20条 SELECT ... LIMIT 0, 20; -- 第2页 SELECT ... LIMIT 20, 20;不过 LIMIT 深分页有个性能坑。当你写LIMIT 100000, 20时MySQL 依然会把前面 100020 行都查出来再丢掉前 100000 行。数据量大后面会越来越慢。优化方案是通过主键定位SELECT ... WHERE id 100000 ORDER BY id ASC LIMIT 20;这就是基于游标的分页效率高得多。5.2 GROUP BY 与聚合函数的组合用法聚合查询是把多行数据计算成一个结果。最常用的是这几类-- 总数 SELECT COUNT(*) FROM books; -- 平均价格 SELECT AVG(price) FROM books; -- 最高最低价 SELECT MAX(price), MIN(price) FROM books; -- 总库存 SELECT SUM(stock) FROM books;聚合函数经常搭配 GROUP BY 一起用按某个维度分组再分别计算。比如按作者统计书籍数量和平均价格SELECT author, COUNT(*) AS book_count, AVG(price) AS avg_price FROM books GROUP BY author;这条语句的执行逻辑是先按 author 分组将同一作者的多行合并成一组然后对每一组分别计算 COUNT 和 AVG。GROUP BY 之后如果要过滤分组要用 HAVING而不是 WHERESELECT author, COUNT(*) AS book_count FROM books GROUP BY author HAVING COUNT(*) 2;这条语句只返回书籍数量大于等于 2 的作者。WHERE 和 HAVING 的区别是新手比较容易混的点WHERE 在分组之前过滤行不能引用聚合函数HAVING 在分组之后过滤分组可以引用聚合函数举个场景你想统计单价超过 30 元的书里每个作者的书量。应该先 WHERE 过滤价格再 GROUP BY 分组SELECT author, COUNT(*) FROM books WHERE price 30 GROUP BY author;如果写WHERE price 30 AND COUNT(*) 2MySQL 会直接报语法错误因为 WHERE 阶段聚合还没开始计算呢。想一眼看懂聚合查询的结果可以试试配合 ROLLUP 做小计SELECT author, COUNT(*) FROM books GROUP BY author WITH ROLLUP;这个语法会在结果末尾加一行所有作者的总计数做报表时很方便。5.3 实操案例一个完整的报表查询把上面的语句拼装起来我们做一个统计 2024 年出版书籍中每个作者的均价和总库存只保留书籍数量大于等于 2 的作者按总库存降序排列取前 5 名的查询SELECT author, COUNT(*) AS book_count, AVG(price) AS avg_price, SUM(stock) AS total_stock FROM books WHERE published_date 2024-01-01 AND published_date 2025-01-01 GROUP BY author HAVING COUNT(*) 2 ORDER BY total_stock DESC LIMIT 5;这个查询包含了一个相对完整的 SQL 执行顺序MySQL 的逻辑处理顺序是这样的FROM确定从哪张表取数WHERE过滤原始行GROUP BY分组HAVING过滤分组SELECT计算并投影需要的字段ORDER BY排序LIMIT取前几行理解执行顺序非常重要它能解释很多为什么类的问题。比如为什么 WHERE 里不能写别名因为 WHERE 执行时 SELECT 还没算完别名根本不存在。写 SQL 的时候按这个顺序去推理基本不会出错。6. 高频报错与排查技巧踩过的坑都在这6.1 随手就能遇到的典型报错整理一下初学者和中级用户最常碰到的报错信息每条我都附上原因和解法。报错信息常见原因解决方案ERROR 1045 (28000): Access denied for user用户名或密码错误或该用户无权限检查账号密码用 root 登录后执行GRANT授权ERROR 1046 (3D000): No database selected没执行 USE 切库执行USE database_name;或者在 SQL 里写成库名.表名ERROR 1054 (42S22): Unknown column字段名拼写错误或该字段不存在执行DESC 表名;查看真实字段名ERROR 1064 (42000): You have an error in your SQL syntax语法错误比如少分号、关键字拼错检查语句末尾是否加分号关键字是否拼写正确ERROR 1062 (23000): Duplicate entry插入数据时主键或唯一键冲突使用INSERT IGNORE或ON DUPLICATE KEY UPDATEERROR 1175 (HY000): Safe update mode在 Workbench 等工具里执行 UPDATE/DELETE 没写 WHERE要么补 WHERE 条件要么临时关闭安全模式SET SQL_SAFE_UPDATES 0;ERROR 1265 (01000): Data truncated for column插入的数据超出字段范围或格式不对修改字段类型或修正插入的数据格式ERROR 1366 (HY000): Incorrect string value字符集问题比如 utf8 存 emoji把相关表和字段改成 utf8mb4ERROR 1146 (42S02): Table doesnt exist表名写错或没切库检查表名大小写和当前所在库ERROR 1064大概是新手遇到最多的报错。看到这个报错别慌MySQL 会在报错信息里指出语法错误的位置在箭头所指附近仔细检查那一行附近的拼写和符号。很多时候是中文输入法误入了英文标点尤其引号和分号肉眼很难分辨但 MySQL 会非常诚实地说语法错误。6.2 字符集问题的真相与处理字符集问题容易让人抓狂因为表面上看不出原因。常见的现象是插入中文后查询出来是问号或者插入带 emoji 的文本报错。字符集有四个层级数据库级、表级、字段级、连接级。任何一个不一致都可能出问题。最稳妥的方案是统一 utf8mb4-- 修改当前连接的字符集 SET NAMES utf8mb4;这是一条非常实用的语句每次建立连接后建议都执行一下。它同时修改了客户端、连接和返回结果的字符集能避免大部分乱码问题。如果表已经建好需要修改字段字符集ALTER TABLE books CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;这条语句会修改表中所有字符串字段的字符集。数据量大的时候会锁表线上操作要谨慎但测试环境和初期开发无所谓。还有个容易忽略的点WHERE author 张三查不到数据可能不是因为数据不存在而是因为连接字符集不对导致传入的中文已经变成了别的编码。遇到查询结果不对劲先执行SET NAMES utf8mb4;再重试往往能解决问题。6.3 容易被忽视的操作安全常识有些操作习惯看起来不影响功能但关键时刻能救命。第一个要说的是不要轻易用 root 连接应用。root 是超级管理员一旦应用被注入攻击者拿到 root 就等于拿下了整个数据库。应该为应用单独创建账号只授予必要权限-- 创建应用专用账号 CREATE USER app_userlocalhost IDENTIFIED BY strong_password; -- 只授予 demo 库的查询、插入、更新、删除权限 GRANT SELECT, INSERT, UPDATE, DELETE ON demo.* TO app_userlocalhost; -- 刷新权限 FLUSH PRIVILEGES;第二个习惯是执行影响大批量数据的语句前先查一下影响范围。比如要删除某作者的全部书籍-- 先查看影响数据 SELECT id, title FROM books WHERE author 张三; -- 确认没问题再删 DELETE FROM books WHERE author 张三;第三个习惯是重要操作前先备份。备份单库用 mysqldump 非常方便mysqldump -u root -p demo demo_backup_20240115.sql恢复时mysql -u root -p demo demo_backup_20240115.sql这几个习惯养成了哪怕操作失误损失也可控。我从一个朋友那学到一句话数据库操作里稳比快重要一万倍。这话一点不夸张。6.4 调优理念先学会看懂执行计划虽然是基础操作文章但我觉得有必要提前打个底当你写的 SQL 变慢时要知道怎么定位问题。MySQL 提供了执行计划工具EXPLAIN SELECT * FROM books WHERE author 张三;执行结果里会显示一张表重点关注这几列type访问类型从好到差依次是 system、const、eq_ref、ref、range、index、ALL。ALL 代表全表扫描数据量大时是比较慢的possible_keys可能用到的索引key实际用到的索引rows预估扫描的行数Extra额外信息如果出现Using filesort说明排序没走索引性能可能有问题刚学 MySQL 时不必把所有列都吃透能看懂type为 ALL 意味着全表扫描就够了。比如上面的查询如果 author 字段没有索引type 就是 ALL在大表中会全表扫描。解决办法是给 author 字段加索引ALTER TABLE books ADD INDEX idx_author (author);加完索引再执行 EXPLAINtype 会变成 refrows 也会大幅减少。这就是索引的价值——把查询从扫全表变成按目录查。我建议所有写 SQL 的人哪怕只是入门也把 EXPLAIN 当成观察工具多用几次就自然理解了索引的重要性。7. 从入门到顺手我的几条实操心得基础操作语句学完之后真正决定你能不能从会写到写得稳的是下面这几条心得。第一写 SQL 之前先理清需求层级。是查库、查表还是查数据是改结构还是改数据不同层级对应完全不同的语句操作风险也不同。先在心里把这句话问完能避免大半误操作。第二一定要养成先 SELECT 再 UPDATE/DELETE 的习惯。这习惯成本极低但每次都能帮你确认 WHERE 条件是否正确直接影响的数据量是否在预期内。我见过太多因为少个空格、多个逗号导致数据全改错的案例全表更新之后只能靠备份恢复那种痛苦经历一次就够。第三多使用 SHOW 系列命令观察现状。写代码前用SHOW CREATE TABLE看建表语句用DESC看字段信息用SHOW INDEX FROM看索引情况用EXPLAIN看执行计划。这些命令不产生数据变更但能提供大量信息相当于动手干活之前先观察地形永远不亏。第四报错信息是最好的老师。MySQL 的报错其实给足了信息量只是新手往往一看到ERROR就慌了。冷静下来把报错信息完整读一遍它告诉你的往往比搜索引擎更准确。再配合SHOW系列命令查看当前状态大部分问题自己就能解决。练习基础操作不需要复杂的业务场景一个简单的表几十条数据反复做增删改查就足够了。把常见语句练到肌肉记忆后面学联表、子查询、窗口函数时才不会感觉吃力。MySQL 基础语句用熟了数据库的整个大门就算打开了。