1. MySQL增删改查基础操作全解析
作为关系型数据库的经典代表,MySQL的增删改查(CRUD)操作是每位开发者必须掌握的看家本领。我在实际项目中发现,很多看似简单的SQL语句背后,藏着不少影响性能的细节陷阱。今天我们就用生产级的标准,重新梳理这些基础操作的正确姿势。
提示:本文所有示例基于MySQL 8.0版本,部分语法在5.7及以下版本可能需要调整
1.1 环境准备与数据样例
在开始实操前,我们先建立一个标准的测试环境。推荐使用Docker快速部署:
bash复制docker run --name mysql-crud -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d mysql:8.0
创建测试用的学生信息表,这个结构包含了常见的字段类型:
sql复制CREATE TABLE students (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL COMMENT '学生姓名',
gender ENUM('M','F') DEFAULT 'M',
birth_date DATE,
class_id INT,
score DECIMAL(5,2),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_class (class_id),
INDEX idx_name (name)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据插入操作详解
2.1 基础插入语法
最基本的单条插入语句大家都会:
sql复制INSERT INTO students (name, gender, birth_date, class_id, score)
VALUES ('张三', 'M', '2005-08-12', 101, 89.5);
但实际项目中,我们更推荐使用这种包含字段名的完整写法,而不是省略字段列表的简写方式。原因有三:
- 表结构变更时语句不会报错
- 明确知道插入哪些字段
- 字段顺序可以与表定义不同
2.2 批量插入性能优化
当需要插入多条数据时,绝对不要用循环执行单条INSERT语句!应该使用批量插入语法:
sql复制INSERT INTO students (name, gender, class_id, score) VALUES
('李四', 'F', 102, 92.0),
('王五', 'M', 101, 78.5),
('赵六', 'F', 103, 85.0);
实测对比:插入1000条数据
- 单条INSERT循环:约12秒
- 批量INSERT:仅0.8秒
注意:MySQL服务器默认max_allowed_packet=4MB,超大数据量需要分批次插入
2.3 高级插入技巧
2.3.1 INSERT IGNORE
当遇到唯一键冲突时跳过而不是报错:
sql复制INSERT IGNORE INTO students (id, name) VALUES (1, '张三');
2.3.2 REPLACE INTO
先删除冲突记录再插入新记录:
sql复制REPLACE INTO students (id, name) VALUES (1, '张三新名字');
2.3.3 ON DUPLICATE KEY UPDATE
遇到冲突时执行更新操作:
sql复制INSERT INTO students (id, name, score)
VALUES (1, '张三', 90.0)
ON DUPLICATE KEY UPDATE score = VALUES(score);
3. 数据查询的艺术
3.1 基础查询优化
sql复制-- 反例:全表扫描
SELECT * FROM students;
-- 正例:按需查询+使用索引
SELECT id, name, score FROM students WHERE class_id = 101;
关键点:
- 永远不要在生产环境用SELECT *
- WHERE条件尽量使用索引字段
- 大数据量查询要加LIMIT限制
3.2 高级查询技巧
3.2.1 分页查询优化
常见错误写法(大数据量时性能极差):
sql复制SELECT * FROM students LIMIT 100000, 10;
优化方案(利用主键索引):
sql复制SELECT * FROM students
WHERE id > (SELECT id FROM students ORDER BY id LIMIT 100000, 1)
LIMIT 10;
3.2.2 聚合函数使用
sql复制-- 统计各班平均分(保留两位小数)
SELECT
class_id,
COUNT(*) AS student_count,
ROUND(AVG(score), 2) AS avg_score,
MAX(score) AS max_score,
MIN(score) AS min_score
FROM students
GROUP BY class_id
HAVING avg_score > 80.00;
3.2.3 窗口函数(MySQL 8.0+)
sql复制-- 计算班级内成绩排名
SELECT
name,
class_id,
score,
RANK() OVER (PARTITION BY class_id ORDER BY score DESC) AS class_rank
FROM students;
4. 数据更新操作要点
4.1 基础更新语法
sql复制UPDATE students
SET score = 95.0, updated_at = NOW()
WHERE id = 1;
4.2 批量更新陷阱
危险操作(没有WHERE条件会更新全表):
sql复制-- 会更新所有记录!
UPDATE students SET score = 60.0;
安全写法:
sql复制-- 明确指定条件
UPDATE students SET score = score + 5
WHERE class_id = 101 AND score < 90.0;
4.3 JOIN更新
sql复制-- 根据班级表更新学生信息
UPDATE students s
JOIN classes c ON s.class_id = c.id
SET s.score = s.score + c.bonus
WHERE c.grade = '2023';
5. 数据删除的安全操作
5.1 基础删除语法
sql复制-- 删除单条记录
DELETE FROM students WHERE id = 1;
-- 按条件批量删除
DELETE FROM students WHERE score < 60.0;
5.2 清空表的正确姿势
危险操作(不记录binlog,无法回滚):
sql复制TRUNCATE TABLE students;
安全操作:
sql复制-- 可回滚的删除
DELETE FROM students;
-- 重置自增ID
ALTER TABLE students AUTO_INCREMENT = 1;
5.3 软删除设计模式
实际项目中推荐使用软删除:
sql复制-- 添加is_deleted字段
ALTER TABLE students ADD COLUMN is_deleted TINYINT DEFAULT 0;
-- 删除操作变为更新
UPDATE students SET is_deleted = 1 WHERE id = 1;
-- 查询时排除已删除数据
SELECT * FROM students WHERE is_deleted = 0;
6. 事务与锁机制
6.1 基础事务控制
sql复制START TRANSACTION;
UPDATE account SET balance = balance - 100 WHERE user_id = 1;
UPDATE account SET balance = balance + 100 WHERE user_id = 2;
-- 确认无误后提交
COMMIT;
-- 出现异常时回滚
-- ROLLBACK;
6.2 事务隔离级别
查看当前隔离级别:
sql复制SELECT @@transaction_isolation;
设置隔离级别(需在事务开始前):
sql复制SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
7. 常见问题排查
7.1 性能问题
慢查询日志分析:
sql复制-- 查看是否开启慢查询日志
SHOW VARIABLES LIKE 'slow_query%';
-- 查看慢查询阈值(秒)
SHOW VARIABLES LIKE 'long_query_time';
EXPLAIN使用:
sql复制EXPLAIN SELECT * FROM students WHERE class_id = 101;
关键指标:
- type:最好达到ref或range级别
- rows:预估扫描行数
- Extra:避免出现"Using filesort"
7.2 连接问题
连接数查看:
sql复制SHOW STATUS LIKE 'Threads_connected';
最大连接数设置:
sql复制-- 临时设置
SET GLOBAL max_connections = 200;
-- 永久生效需要修改my.cnf
[mysqld]
max_connections = 200
8. 最佳实践总结
-
字段选择原则:
- 永远明确指定字段列表
- TEXT/BLOB字段单独查询
- 避免SELECT * 查询
-
索引使用规范:
- WHERE条件使用索引字段
- 避免对索引列使用函数
- 注意最左前缀原则
-
事务控制要点:
- 事务要尽可能短小
- 避免在事务中进行网络IO
- 合理设置隔离级别
-
安全备份策略:
- 定期执行mysqldump
- 重要操作前创建临时备份表
- 考虑使用binlog恢复
我在实际项目中总结的一个小技巧:对于高频查询但很少变更的配置表,可以添加应用层缓存,同时设置一个version字段,当数据变更时更新version值,这样应用可以快速判断缓存是否过期。
