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 可恢复

最佳实践:

  1. 始终使用WHERE条件,避免误删全表
  2. 删除前先查询确认
  3. 重要操作使用事务
  4. 大批量删除分批进行
  5. 考虑使用软删除
  6. 定期备份重要数据

下一步,让我们学习数据查询!

最后更新:2026-03-26