1. MySQL基础操作概述
MySQL作为最流行的开源关系型数据库之一,其核心操作可以归纳为CRUD(Create, Read, Update, Delete)。对于开发者而言,熟练掌握这些基础操作是数据库应用的基石。不同于简单的命令记忆,理解每个操作背后的执行机制和适用场景,才能真正发挥MySQL的性能优势。
在实际项目中,我曾遇到不少初级开发者虽然能写出基本的SQL语句,但当面对复杂查询或性能优化时却束手无策。究其原因,往往是对基础操作的理解停留在表面。比如,一个简单的SELECT查询,不同的写法可能导致完全不同的执行计划;UPDATE操作不加WHERE条件的灾难性后果;DELETE与TRUNCATE的本质区别等。这些问题在日常开发中频繁出现,值得我们深入探讨。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 数据查询(SELECT)详解
2.1 基础查询语法与执行原理
最基本的SELECT语句格式如下:
sql复制SELECT column1, column2 FROM table_name WHERE condition;
这个看似简单的语句背后,MySQL执行引擎会经历解析、优化、执行三个阶段。在解析阶段,MySQL会检查语法正确性;优化阶段则根据表结构、索引情况选择最优执行计划;最后执行阶段获取数据。
一个常见的误区是使用SELECT *查询所有字段。在开发测试阶段这确实方便,但在生产环境中会带来不必要的性能开销。我曾优化过一个系统,仅将SELECT *改为明确指定字段,查询速度就提升了30%,因为减少了不必要的数据传输。
2.2 条件查询与运算符
WHERE子句支持丰富的运算符:
- 比较运算符:=, <>, >, <, >=, <=
- 逻辑运算符:AND, OR, NOT
- 范围查询:BETWEEN, IN
- 模糊查询:LIKE
特别注意NULL值的判断必须使用IS NULL或IS NOT NULL,因为NULL与任何值的比较(包括NULL本身)结果都是UNKNOWN而非TRUE或FALSE。这是很多初学者容易犯错的地方。
2.3 排序与分页
ORDER BY子句用于结果排序:
sql复制SELECT * FROM products ORDER BY price DESC, stock ASC;
分页查询在Web应用中极为常见,标准写法是:
sql复制SELECT * FROM orders LIMIT 10 OFFSET 20; -- 跳过20条,取10条
在MySQL 8.0+中也可以使用更符合SQL标准的写法:
sql复制SELECT * FROM orders LIMIT 20, 10;
注意:大数据量分页时,OFFSET效率会急剧下降。我曾处理过一个案例,当OFFSET超过100万时查询耗时达到数秒。解决方案是使用"记住上次查询位置"的方式替代传统分页。
2.4 聚合与分组
GROUP BY配合聚合函数(COUNT, SUM, AVG, MAX, MIN等)可以实现数据统计:
sql复制SELECT department, AVG(salary)
FROM employees
GROUP BY department
HAVING AVG(salary) > 5000;
这里要区分WHERE和HAVING:
- WHERE在分组前过滤,作用于原始数据
- HAVING在分组后过滤,作用于聚合结果
3. 数据插入(INSERT)操作
3.1 基本插入语法
最基础的INSERT语句:
sql复制INSERT INTO users (username, email) VALUES ('john', 'john@example.com');
多行插入可以提升批量插入效率:
sql复制INSERT INTO products (name, price) VALUES
('Product A', 10.99),
('Product B', 20.99),
('Product C', 30.99);
3.2 INSERT...SELECT模式
这种模式可以将查询结果直接插入到表中:
sql复制INSERT INTO vip_users (user_id, join_date)
SELECT id, created_at FROM users WHERE score > 1000;
我在数据迁移项目中经常使用这种模式,比先查询再插入的方式效率高很多。
3.3 ON DUPLICATE KEY UPDATE
处理主键或唯一键冲突的神器:
sql复制INSERT INTO inventory (product_id, quantity)
VALUES (1001, 10)
ON DUPLICATE KEY UPDATE quantity = quantity + 10;
这个语法实现了"存在则更新,不存在则插入"的逻辑,避免了先查询判断的繁琐操作。
4. 数据更新(UPDATE)操作
4.1 基础更新语法
UPDATE语句基本结构:
sql复制UPDATE table_name SET column1 = value1, column2 = value2 WHERE condition;
警告:忘记加WHERE条件会更新整张表!这是最危险的错误之一。建议在执行UPDATE前先用相同条件的SELECT确认影响范围。
4.2 多表更新
MySQL支持JOIN方式的更新:
sql复制UPDATE orders o
JOIN users u ON o.user_id = u.id
SET o.status = 'VIP'
WHERE u.vip_level > 3;
4.3 使用子查询更新
基于其他表的查询结果更新:
sql复制UPDATE products p
SET p.price = p.price * 1.1
WHERE p.category_id IN (
SELECT id FROM categories WHERE type = 'premium'
);
注意:MySQL对同一表的查询和更新有限制,可能需要使用临时表或JOIN方式解决。
5. 数据删除(DELETE)操作
5.1 基础删除语法
DELETE语句基本形式:
sql复制DELETE FROM table_name WHERE condition;
与UPDATE类似,忘记WHERE条件会清空整张表!建议先备份重要数据。
5.2 多表删除
MySQL支持同时从多个表删除相关数据:
sql复制DELETE o, oi
FROM orders o
JOIN order_items oi ON o.id = oi.order_id
WHERE o.status = 'cancelled';
5.3 DELETE与TRUNCATE的区别
两者都能清空表,但有重要区别:
| 特性 | DELETE | TRUNCATE |
|---|---|---|
| 执行速度 | 较慢,逐行删除 | 快,直接删除数据文件 |
| 事务 | 可回滚 | 不可回滚 |
| 触发器 | 会触发 | 不会触发 |
| 自增ID | 不重置 | 重置为初始值 |
| WHERE条件 | 支持 | 不支持 |
在需要快速清空大表时,TRUNCATE是更好的选择,但要注意它无法回滚。
6. 事务处理与并发控制
6.1 基本事务操作
MySQL默认使用自动提交模式,要使用事务需要显式控制:
sql复制START TRANSACTION;
UPDATE accounts SET balance = balance - 100 WHERE id = 1;
UPDATE accounts SET balance = balance + 100 WHERE id = 2;
COMMIT; -- 或 ROLLBACK;
6.2 隔离级别
MySQL支持四种隔离级别:
- READ UNCOMMITTED(读未提交)
- READ COMMITTED(读已提交)
- REPEATABLE READ(可重复读,MySQL默认)
- SERIALIZABLE(串行化)
设置方法:
sql复制SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
选择适当的隔离级别需要在性能和数据一致性之间取得平衡。我曾遇到一个电商系统使用默认的REPEATABLE READ导致大量锁等待,调整为READ COMMITTED后性能显著提升。
6.3 锁机制
MySQL主要有两种锁:
- 共享锁(S锁):SELECT ... LOCK IN SHARE MODE
- 排他锁(X锁):SELECT ... FOR UPDATE
在库存扣减等场景下,正确使用锁可以避免超卖:
sql复制START TRANSACTION;
SELECT stock FROM products WHERE id = 1001 FOR UPDATE;
-- 检查库存充足后执行更新
UPDATE products SET stock = stock - 1 WHERE id = 1001;
COMMIT;
7. 性能优化技巧
7.1 索引优化
EXPLAIN是分析查询性能的利器:
sql复制EXPLAIN SELECT * FROM orders WHERE user_id = 100;
关键指标:
- type:最好达到ref或range级别
- possible_keys:可能使用的索引
- key:实际使用的索引
- rows:预估扫描行数
7.2 查询重写
将子查询改写为JOIN通常能提升性能:
sql复制-- 低效的子查询
SELECT * FROM products
WHERE category_id IN (SELECT id FROM categories WHERE type = 'electronics');
-- 高效的JOIN写法
SELECT p.* FROM products p
JOIN categories c ON p.category_id = c.id
WHERE c.type = 'electronics';
7.3 批量操作
批量插入比单条插入效率高很多。我曾测试过,1000条数据批量插入比单条插入快50倍以上。使用预处理语句(Prepared Statement)也能提升重复查询的性能。
8. 常见问题解决方案
8.1 连接数过多
错误信息:"Too many connections"
解决方案:
- 临时增加连接数:
sql复制SET GLOBAL max_connections = 500;
- 优化应用使用连接池
- 检查是否有连接泄漏
8.2 死锁问题
分析死锁日志:
sql复制SHOW ENGINE INNODB STATUS;
预防措施:
- 保持事务简短
- 按固定顺序访问多张表
- 使用合适的索引减少锁定范围
8.3 大数据量删除
直接删除大表数据可能导致锁表时间过长。替代方案:
- 分批删除:
sql复制DELETE FROM logs WHERE created_at < '2020-01-01' LIMIT 1000;
- 新建表替换:
sql复制CREATE TABLE new_logs LIKE logs;
INSERT INTO new_logs SELECT * FROM logs WHERE created_at >= '2020-01-01';
RENAME TABLE logs TO old_logs, new_logs TO logs;
DROP TABLE old_logs;
在实际项目中,我经常使用第二种方法处理数亿条日志数据的清理工作,几乎不影响线上服务。
