MySQL数据删除 #
一、DELETE语句概述 #
1.1 基本语法 #
sql
DELETE FROM table_name
WHERE condition;
1.2 示例表结构 #
sql
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50),
age INT,
email VARCHAR(100),
status TINYINT DEFAULT 1
);
INSERT INTO users (name, age, email, status) VALUES
('John', 25, 'john@example.com', 1),
('Jane', 30, 'jane@example.com', 1),
('Bob', 28, 'bob@example.com', 0),
('Alice', 22, 'alice@example.com', 0);
二、基本删除 #
2.1 条件删除 #
sql
-- 根据ID删除
DELETE FROM users WHERE id = 1;
-- 根据名称删除
DELETE FROM users WHERE name = 'John';
-- 多条件删除
DELETE FROM users WHERE age > 30 AND status = 0;
2.2 删除所有数据 #
sql
-- 危险操作!删除所有数据
DELETE FROM users;
-- 建议先查询确认
SELECT COUNT(*) FROM users;
三、条件删除 #
3.1 使用各种条件 #
sql
-- 使用IN条件
DELETE FROM users WHERE id IN (1, 2, 3);
-- 使用BETWEEN条件
DELETE FROM users WHERE age BETWEEN 20 AND 25;
-- 使用LIKE条件
DELETE FROM users WHERE email LIKE '%@old.com';
-- 使用IS NULL条件
DELETE FROM users WHERE email IS NULL;
3.2 使用子查询 #
sql
-- 删除满足子查询条件的记录
DELETE FROM users
WHERE id IN (
SELECT user_id FROM orders
WHERE status = 'cancelled'
);
-- 使用NOT IN
DELETE FROM users
WHERE id NOT IN (
SELECT DISTINCT user_id FROM orders
);
-- 使用EXISTS
DELETE FROM users u
WHERE EXISTS (
SELECT 1 FROM logs l
WHERE l.user_id = u.id AND l.action = 'spam'
);
3.3 多表关联删除 #
sql
-- 删除没有订单的用户
DELETE u FROM users u
LEFT JOIN orders o ON u.id = o.user_id
WHERE o.id IS NULL;
-- 根据关联表条件删除
DELETE u FROM users u
JOIN user_status s ON u.id = s.user_id
WHERE s.status = 'banned';
四、ORDER BY和LIMIT #
4.1 限制删除数量 #
sql
-- 只删除前10条
DELETE FROM logs
WHERE level = 'debug'
LIMIT 10;
4.2 按顺序删除 #
sql
-- 删除最早的100条日志
DELETE FROM logs
ORDER BY created_at ASC
LIMIT 100;
-- 删除最后10条
DELETE FROM logs
ORDER BY created_at DESC
LIMIT 10;
五、TRUNCATE语句 #
5.1 基本语法 #
sql
TRUNCATE TABLE table_name;
-- 示例
TRUNCATE TABLE logs;
5.2 TRUNCATE与DELETE对比 #
| 特性 | DELETE | TRUNCATE |
|---|---|---|
| 类型 | DML | DDL |
| 条件 | 支持WHERE | 不支持条件 |
| 速度 | 较慢 | 更快 |
| 回滚 | 可以回滚 | 不能回滚 |
| 自增ID | 保留 | 重置为1 |
| 触发器 | 触发 | 不触发 |
| 影响行数 | 返回实际行数 | 返回0 |
5.3 使用场景 #
sql
-- 使用DELETE:需要条件删除或回滚
DELETE FROM users WHERE status = 0;
-- 使用TRUNCATE:清空整个表
TRUNCATE TABLE logs;
TRUNCATE TABLE temp_data;
六、安全删除 #
6.1 开启安全模式 #
sql
-- 查看安全模式状态
SHOW VARIABLES LIKE 'sql_safe_updates';
-- 开启安全模式
SET sql_safe_updates = 1;
-- 关闭安全模式
SET sql_safe_updates = 0;
6.2 安全模式限制 #
sql
-- 安全模式下,必须使用键列作为条件
-- 错误示例:
DELETE FROM users;
-- ERROR 1175 (HY000): You are using safe update mode
-- 正确示例:
DELETE FROM users WHERE id = 1;
6.3 删除前检查 #
sql
-- 删除前先查询
SELECT * FROM users WHERE status = 0;
-- 确认数量
SELECT COUNT(*) FROM users WHERE status = 0;
-- 使用事务
START TRANSACTION;
DELETE FROM users WHERE status = 0;
-- 确认结果
SELECT COUNT(*) FROM users WHERE status = 0;
-- 确认无误后提交
COMMIT;
-- 如有问题回滚
ROLLBACK;
七、软删除 #
7.1 软删除概念 #
sql
-- 不真正删除,而是标记为已删除
-- 添加删除标记字段
ALTER TABLE users ADD COLUMN is_deleted TINYINT DEFAULT 0;
ALTER TABLE users ADD COLUMN deleted_at DATETIME;
-- 软删除操作
UPDATE users
SET is_deleted = 1, deleted_at = NOW()
WHERE id = 1;
-- 查询时排除已删除记录
SELECT * FROM users WHERE is_deleted = 0;
-- 恢复删除
UPDATE users
SET is_deleted = 0, deleted_at = NULL
WHERE id = 1;
7.2 软删除优势 #
| 优势 | 说明 |
|---|---|
| 数据恢复 | 可以恢复误删数据 |
| 审计追踪 | 保留删除记录 |
| 数据完整性 | 维护关联数据 |
| 合规要求 | 满足数据保留要求 |
7.3 定期清理 #
sql
-- 定期清理超过30天的软删除数据
DELETE FROM users
WHERE is_deleted = 1
AND deleted_at < DATE_SUB(NOW(), INTERVAL 30 DAY);
八、级联删除 #
8.1 外键级联删除 #
sql
-- 创建带级联删除的表
CREATE TABLE departments (
id INT PRIMARY KEY,
name VARCHAR(50)
);
CREATE TABLE employees (
id INT PRIMARY KEY,
name VARCHAR(50),
department_id INT,
FOREIGN KEY (department_id)
REFERENCES departments(id)
ON DELETE CASCADE
);
-- 删除部门时,自动删除该部门的所有员工
DELETE FROM departments WHERE id = 1;
8.2 手动级联删除 #
sql
-- 先删除从表记录
DELETE FROM employees WHERE department_id = 1;
-- 再删除主表记录
DELETE FROM departments WHERE id = 1;
九、删除性能优化 #
9.1 使用索引 #
sql
-- 确保WHERE条件使用索引
-- 查看执行计划
EXPLAIN DELETE FROM users WHERE email = 'john@example.com';
-- 如果email有索引,删除更快
9.2 分批删除 #
sql
-- 大批量删除分批进行
-- 每次删除1000条
DELETE FROM logs
WHERE created_at < '2023-01-01'
LIMIT 1000;
-- 循环执行直到影响行数为0
9.3 临时禁用索引 #
sql
-- 大批量删除时临时禁用索引
ALTER TABLE logs DISABLE KEYS;
DELETE FROM logs WHERE created_at < '2023-01-01';
ALTER TABLE logs ENABLE KEYS;
十、常见错误处理 #
10.1 外键约束错误 #
sql
-- 错误信息
DELETE FROM departments WHERE id = 1;
-- ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails
-- 解决方案:先删除关联记录
DELETE FROM employees WHERE department_id = 1;
DELETE FROM departments WHERE id = 1;
-- 或使用级联删除
10.2 权限不足 #
sql
-- 错误信息
DELETE FROM users;
-- ERROR 1142 (42000): DELETE command denied to user 'user'@'localhost' for table 'users'
-- 解决方案:使用root用户授权
GRANT DELETE ON mydb.* TO 'user'@'localhost';
FLUSH PRIVILEGES;
10.3 表不存在 #
sql
-- 错误信息
DELETE FROM non_existent_table;
-- ERROR 1146 (42S02): Table 'mydb.non_existent_table' doesn't exist
-- 解决方案:检查表名
SHOW TABLES LIKE 'users';
十一、删除后恢复 #
11.1 使用事务回滚 #
sql
START TRANSACTION;
DELETE FROM users WHERE id = 1;
-- 发现错误,回滚
ROLLBACK;
11.2 使用备份恢复 #
bash
# 从备份恢复单表
mysql -u root -p mydb < users_backup.sql
# 从全量备份恢复
mysql -u root -p < full_backup.sql
11.3 使用二进制日志恢复 #
bash
# 查看binlog
mysqlbinlog /var/lib/mysql/mysql-bin.000001
# 恢复到指定时间点
mysqlbinlog --stop-datetime="2024-01-15 10:00:00" /var/lib/mysql/mysql-bin.000001 | mysql -u root -p
十二、删除统计 #
12.1 查看影响行数 #
sql
DELETE FROM users WHERE status = 0;
-- Query OK, 3 rows affected
-- 在应用程序中获取
-- PHP: $affected = $pdo->rowCount();
// Java: int affected = statement.executeUpdate();
12.2 删除前后统计 #
sql
-- 删除前统计
SELECT COUNT(*) AS before_count FROM users WHERE status = 0;
-- 执行删除
DELETE FROM users WHERE status = 0;
-- 删除后统计
SELECT COUNT(*) AS after_count FROM users WHERE status = 0;
十三、总结 #
删除数据要点:
| 操作 | 语法 | 特点 |
|---|---|---|
| 条件删除 | DELETE FROM … WHERE | 支持条件,可回滚 |
| 全表删除 | DELETE FROM | 慢,保留自增ID |
| 清空表 | TRUNCATE TABLE | 快,重置自增ID |
| 软删除 | UPDATE … SET is_deleted=1 | 可恢复 |
最佳实践:
- 始终使用WHERE条件,避免误删全表
- 删除前先查询确认
- 重要操作使用事务
- 大批量删除分批进行
- 考虑使用软删除
- 定期备份重要数据
下一步,让我们学习数据查询!
最后更新:2026-03-26