我是二娃呀 發表於 2025-12-25 08:30:57

MySQL表数据删除与清理的最佳实践

<div id="navCategory"><h5 class="catalogue">目录</h5><ul class="first_class_ul"><li><a href="#_label0">一、删除表:先&ldquo;隔离&rdquo;再&ldquo;删除&rdquo;,避免误删风险</a></li><ul class="second_class_ul"><li><a href="#_lab2_0_0">1.1 操作步骤(以表t1为例)</a></li><ul class="third_class_ul"><li><a href="#_label3_0_0_0">步骤1:创建测试表(模拟业务表)</a></li><li><a href="#_label3_0_0_1">步骤2:重命名表,实现&ldquo;隔离&rdquo;</a></li><li><a href="#_label3_0_0_2">步骤3:观察依赖,确认安全</a></li><li><a href="#_label3_0_0_3">步骤4:最终删除备份表</a></li></ul><li><a href="#_lab2_0_1">1.2 核心原理与注意事项</a></li><ul class="third_class_ul"></ul></ul><li><a href="#_label1">二、清空表:选对工具(truncate),避免空间浪费与主从延迟</a></li><ul class="second_class_ul"><li><a href="#_lab2_1_2">2.1 实验对比:delete vs truncate</a></li><ul class="third_class_ul"><li><a href="#_label3_1_2_4">步骤1:准备测试数据(10万行)</a></li><li><a href="#_label3_1_2_5">步骤2:查看数据文件大小(InnoDB表的.ibd文件)</a></li><li><a href="#_label3_1_2_6">步骤3:用delete清空表,观察空间变化</a></li><li><a href="#_label3_1_2_7">步骤4:用truncate清空表,观察空间变化</a></li></ul><li><a href="#_lab2_1_3">2.2 关键差异:delete vs truncate</a></li><ul class="third_class_ul"></ul><li><a href="#_lab2_1_4">2.3 注意事项</a></li><ul class="third_class_ul"></ul></ul><li><a href="#_label2">三、不归档删除部分数据:避免大事务,用批量删除或工具</a></li><ul class="second_class_ul"><li><a href="#_lab2_2_5">3.1 方案1:循环批量删除(适合中小数据量)</a></li><ul class="third_class_ul"><li><a href="#_label3_2_5_8">核心逻辑:</a></li><li><a href="#_label3_2_5_9">操作步骤:</a></li><li><a href="#_label3_2_5_10">验证结果:</a></li></ul><li><a href="#_lab2_2_6">3.2 方案2:用pt-archiver工具(适合大数据量)</a></li><ul class="third_class_ul"><li><a href="#_label3_2_6_11">步骤1:安装Percona Toolkit(以CentOS为例)</a></li><li><a href="#_label3_2_6_12">步骤2:创建工具专用用户(授予权限)</a></li><li><a href="#_label3_2_6_13">步骤3:执行删除(不归档,仅删除)</a></li><li><a href="#_label3_2_6_14">统计结果示例:</a></li></ul></ul><li><a href="#_label3">四、归档删除部分数据:先迁移再删除,兼顾数据保留与空间回收</a></li><ul class="second_class_ul"><li><a href="#_lab2_3_7">4.1 操作步骤(用pt-archiver实现归档+删除)</a></li><ul class="third_class_ul"><li><a href="#_label3_3_7_15">步骤1:准备归档环境</a></li><li><a href="#_label3_3_7_16">步骤2:在归档库创建表结构</a></li><li><a href="#_label3_3_7_17">步骤3:归档+删除(pt-archiver)</a></li><li><a href="#_label3_3_7_18">步骤4:验证归档与删除结果</a></li></ul><li><a href="#_lab2_3_8">4.2 回收delete产生的&ldquo;空洞&rdquo;空间</a></li><ul class="third_class_ul"></ul></ul><li><a href="#_label4">五、分区表删除:按分区清理,效率翻倍</a></li><ul class="second_class_ul"><li><a href="#_lab2_4_9">5.1 操作步骤(以按年份分区的日志表为例)</a></li><ul class="third_class_ul"><li><a href="#_label3_4_9_19">步骤1:创建RANGE分区表</a></li><li><a href="#_label3_4_9_20">步骤2:插入测试数据</a></li><li><a href="#_label3_4_9_21">步骤3:查看分区数据分布</a></li><li><a href="#_label3_4_9_22">步骤4:删除2016年数据(直接drop分区)</a></li><li><a href="#_label3_4_9_23">步骤5:验证删除结果</a></li></ul><li><a href="#_lab2_4_10">5.2 核心优势与适用场景</a></li><ul class="third_class_ul"></ul></ul><li><a href="#_label5">六、总结:MySQL删除操作的核心原则与场景选型</a></li><ul class="second_class_ul"></ul></ul></div><p>在MySQL运维中,&ldquo;删除&rdquo;操作看似简单,却隐藏着诸多风险&mdash;&mdash;误删表导致数据永久丢失、delete全表引发主从延迟、删数据后磁盘空间不释放&hellip;&hellip;这些问题往往会造成业务中断或资源浪费。本文基于实际运维场景,详细讲解<strong>删除表、清空表、部分数据删除(归档/不归档)、分区表清理</strong>四大核心场景的最佳操作方案,结合实验验证和原理分析,帮你在&ldquo;安全&rdquo;与&ldquo;效率&rdquo;之间找到平衡。</p>
<p class="maodian"><a name="_label0"></a></p><h2>一、删除表:先&ldquo;隔离&rdquo;再&ldquo;删除&rdquo;,避免误删风险</h2>
<p>直接执行<code>DROP TABLE</code>是高危操作&mdash;&mdash;若存在未发现的业务依赖(如定时任务、应用SQL),会瞬间导致服务报错;且误删后恢复成本极高(需从备份恢复,耗时久)。最佳实践是<strong>先重命名表&ldquo;隔离&rdquo;,观察无依赖后再删除</strong>。</p>
<p class="maodian"><a name="_lab2_0_0"></a></p><h3>1.1 操作步骤(以表t1为例)</h3>
<p class="maodian"><a name="_label3_0_0_0"></a></p><h4>步骤1:创建测试表(模拟业务表)</h4>
<div class="jb51code"><pre class="brush:sql;">-- 先删除旧表(若存在),避免冲突
drop table if exists t1;

-- 创建业务表t1(InnoDB引擎,含自增主键和时间字段)
CREATE TABLE `t1` (
`id` int NOT NULL AUTO_INCREMENT,
`a` varchar(20) DEFAULT NULL,-- 业务字段1
`b` int DEFAULT NULL,          -- 业务字段2
`c` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,-- 自动时间戳
PRIMARY KEY (`id`)
) ENGINE=InnoDB CHARSET=utf8mb4 ;
</pre></div>
<p class="maodian"><a name="_label3_0_0_1"></a></p><h4>步骤2:重命名表,实现&ldquo;隔离&rdquo;</h4>
<p>将目标表重命名为&ldquo;备份+日期&rdquo;格式(如<code>t1_bak_20231114</code>),切断业务直接访问:</p>
<div class="jb51code"><pre class="brush:sql;">alter table t1 rename t1_bak_20231114;
</pre></div>
<p class="maodian"><a name="_label3_0_0_2"></a></p><h4>步骤3:观察依赖,确认安全</h4>
<p>重命名后,<strong>观察1-2周</strong>(根据业务周期调整),重点监控:</p>
<ul><li>应用日志:是否出现&ldquo;Table &lsquo;martin.t1&rsquo; doesn&rsquo;t exist&rdquo;错误(排查隐藏依赖);</li><li>数据库进程:是否有定时任务或存储过程调用原表名。</li></ul>
<p>若观察期内无异常,说明表无依赖,可执行删除。</p>
<p class="maodian"><a name="_label3_0_0_3"></a></p><h4>步骤4:最终删除备份表</h4>
<div class="jb51code"><pre class="brush:sql;">drop table t1_bak_20231114;
</pre></div>
<p class="maodian"><a name="_lab2_0_1"></a></p><h3>1.2 核心原理与注意事项</h3>
<ul><li><strong>为什么不直接drop?</strong><br />重命名本质是&ldquo;逻辑隔离&rdquo;,若发现误操作,可快速改回原表名(<code>alter table t1_bak_20231114 rename t1;</code>),恢复成本几乎为0;而drop会直接删除表结构和数据文件,无法快速恢复。</li><li><strong>适用场景</strong>:非紧急删除的冗余表、历史表(如旧业务下线后的废弃表)。</li></ul>
<p class="maodian"><a name="_label1"></a></p><h2>二、清空表:选对工具(truncate),避免空间浪费与主从延迟</h2>
<p>清空表(删除全表数据)时,很多人习惯用<code>DELETE FROM 表名</code>,但该操作存在两大问题:<strong>不释放磁盘空间</strong>、<strong>行模式binlog下产生大量日志导致主从延迟</strong>。正确选择是<code>TRUNCATE TABLE</code>。</p>
<p class="maodian"><a name="_lab2_1_2"></a></p><h3>2.1 实验对比:delete vs truncate</h3>
<p class="maodian"><a name="_label3_1_2_4"></a></p><h4>步骤1:准备测试数据(10万行)</h4>
<div class="jb51code"><pre class="brush:sql;">use martin;

-- 重建表t1
drop table if exists t1;
CREATE TABLE `t1` (
`id` int NOT NULL AUTO_INCREMENT,
`a` varchar(20) DEFAULT NULL,
`b` int DEFAULT NULL,
`c` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB CHARSET=utf8mb4 ;

-- 创建存储过程,插入10万行数据
drop procedure if exists insert_t1;
delimiter ;;-- 临时修改语句结束符,避免与存储过程内;冲突
create procedure insert_t1()
begin
declare i int;
set i=1;
while(i&lt;=100000)do-- 循环插入10万行
    insert into t1(a,b) values(i,i);
    set i=i+1;
end while;
end;;
delimiter ;

-- 执行存储过程,初始化数据
call insert_t1();
</pre></div>
<p class="maodian"><a name="_label3_1_2_5"></a></p><h4>步骤2:查看数据文件大小(InnoDB表的.ibd文件)</h4>
<p>InnoDB表的数据存储在<code>ibd</code>文件中,先查看初始大小:</p>
<div class="jb51code"><pre class="brush:sql;"># 进入MySQL数据目录(需根据实际路径调整,此处为/data/mysql/data/martin)
cd /data/mysql/data/martin
# 查看t1.ibd大小(-h表示人性化显示,如KB/MB)
ll -h t1.ibd
</pre></div>
<p><strong>实验结果</strong>:<code>t1.ibd</code>约12MB(10万行数据)。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122508270261.png" /></p>
<p class="maodian"><a name="_label3_1_2_6"></a></p><h4>步骤3:用delete清空表,观察空间变化</h4>
<div class="jb51code"><pre class="brush:sql;">-- delete全表数据
delete from t1;
</pre></div>
<p>再执行<code>ll -h t1.ibd</code>,<strong>结果</strong>:文件大小仍为12MB,无变化。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122508270281.png" /></p>
<p class="maodian"><a name="_label3_1_2_7"></a></p><h4>步骤4:用truncate清空表,观察空间变化</h4>
<div class="jb51code"><pre class="brush:sql;">-- 先重建表并插入数据(恢复到步骤2状态)
call insert_t1();
-- truncate清空表
truncate table t1;
</pre></div>
<p>再执行<code>ll -h t1.ibd</code>,<strong>结果</strong>:文件大小骤减至112KB(仅保留表结构,释放所有数据空间)。</p>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122508270288.png" /></p>
<p class="maodian"><a name="_lab2_1_3"></a></p><h3>2.2 关键差异:delete vs truncate</h3>
<table><thead><tr><th>对比维度</th><th>DELETE</th><th>TRUNCATE</th></tr></thead><tbody><tr><td>操作类型</td><td>DML(数据操纵语言)</td><td>DDL(数据定义语言)</td></tr><tr><td>空间释放</td><td>不释放(仅标记删除)</td><td>释放(重建表结构)</td></tr><tr><td>binlog记录</td><td>行模式下逐行记录(日志量大)</td><td>仅记录&ldquo; truncate操作&rdquo;(日志量小)</td></tr><tr><td>事务支持</td><td>可回滚(未提交前可撤销)</td><td>不可回滚(执行即生效)</td></tr><tr><td>自增主键重置</td><td>不重置(下次插入从上次ID继续)</td><td>重置(下次插入从1开始)</td></tr></tbody></table>
<p class="maodian"><a name="_lab2_1_4"></a></p><h3>2.3 注意事项</h3>
<ul><li><strong>必须先备份</strong>:无论用哪种方式,清空表前需用<code>mysqldump</code>备份数据(<code>mysqldump -uroot -p martin t1 &gt; t1_bak.sql</code>),避免误清。</li><li><strong>truncate的限制</strong>:若表被外键引用(<code>FOREIGN KEY</code>),无法直接truncate(需先删除外键或清空关联表);而delete可正常执行。</li></ul>
<p class="maodian"><a name="_label2"></a></p><h2>三、不归档删除部分数据:避免大事务,用批量删除或工具</h2>
<p>当需删除表中部分数据(如删除<code>b&lt;50000</code>的历史数据)且无需归档时,直接执行<code>DELETE FROM t2 WHERE b&lt;50000</code>会引发<strong>大事务</strong>&mdash;&mdash;锁表时间长、占用大量undo日志、主从延迟。最佳方案是<strong>批量删除(加limit)</strong> 或用专业工具<code>pt-archiver</code>。</p>
<p class="maodian"><a name="_lab2_2_5"></a></p><h3>3.1 方案1:循环批量删除(适合中小数据量)</h3>
<p class="maodian"><a name="_label3_2_5_8"></a></p><h4>核心逻辑:</h4>
<p>每次删除1000-10000行(根据服务器性能调整),循环执行直到满足条件的数据删完,避免单次删除行数过多。</p>
<p class="maodian"><a name="_label3_2_5_9"></a></p><h4>操作步骤:</h4>
<p>步骤1:准备测试表与数据(10万行)</p>
<div class="jb51code"><pre class="brush:sql;">use martin;

drop table if exists t2;
CREATE TABLE `t2` (      
`id` int NOT NULL AUTO_INCREMENT,
`a` int DEFAULT NULL,
`b` int DEFAULT NULL,
PRIMARY KEY (id),-- 主键索引
key idx_b(b)       -- 为查询条件b创建索引,加速删除
) ENGINE=InnoDB CHARSET=utf8mb4 ;

-- 存储过程插入10万行数据
drop procedure if exists insert_t2;
delimiter ;;
create procedure insert_t2()      
begin
declare i int;               
set i=1;                     
while(i&lt;=100000)do               
    insert into t2(a,b) values(i,i);
    set i=i+1;                     
end while;
end;;
delimiter ;
call insert_t2();
</pre></div>
<p>步骤2:备份数据(安全前提)</p>
<div class="jb51code"><pre class="brush:sql;"># 用mysqldump备份t2表
cd /data/backup
mysqldump -uroot -p martin t2 &gt; t2_bak.sql

# 或创建备份表,复制数据(更快速)
create table t2_bak_1114 like t2;-- 复制表结构
insert into t2_bak_1114 select * from t2;-- 复制数据
</pre></div>
<p>步骤3:循环批量删除</p>
<div class="jb51code"><pre class="brush:sql;">DELIMITER //

CREATE PROCEDURE delete_t2()
BEGIN
    REPEAT
      DELETE FROM t2 WHERE b &lt; 50000 LIMIT 1000;
    UNTIL ROW_COUNT() = 0 END REPEAT;
   
    SELECT '删除完成' AS result;
END //

DELIMITER ;
</pre></div>
<p class="maodian"><a name="_label3_2_5_10"></a></p><h4>验证结果:</h4>
<div class="jb51code"><pre class="brush:sql;">-- 确认删除效果(应返回0)
select count(*) from t2 where b &lt; 50000;
-- 剩余数据量(应返回50000)
select count(*) from t2 where b &gt;= 50000;
</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122508270294.png" /></p>
<p class="maodian"><a name="_lab2_2_6"></a></p><h3>3.2 方案2:用pt-archiver工具(适合大数据量)</h3>
<p><code>pt-archiver</code>是Percona Toolkit中的工具,专为批量归档/删除MySQL数据设计,支持按条件批量处理、统计进度,且能避免大事务。</p>
<p class="maodian"><a name="_label3_2_6_11"></a></p><h4>步骤1:安装Percona Toolkit(以CentOS为例)</h4>
<div class="jb51code"><pre class="brush:bash;"># 安装依赖
yum install -y perl-DBI perl-DBD-MySQL perl-Time-HiRes perl-IO-Socket-SSL

# 下载并安装Percona Toolkit
wget https://downloads.percona.com/downloads/percona-toolkit/3.5.1/binary/redhat/8/x86_64/percona-toolkit-3.5.1-1.el8.x86_64.rpm
rpm -ivh percona-toolkit-3.5.1-1.el8.x86_64.rpm

# 验证安装(查看版本)
pt-archiver --version
</pre></div>
<p class="maodian"><a name="_label3_2_6_12"></a></p><h4>步骤2:创建工具专用用户(授予权限)</h4>
<div class="jb51code"><pre class="brush:sql;">-- 创建dba用户,允许192.168网段访问
CREATE USER 'dba'@'192.168.%' IDENTIFIED WITH MYSQL_NATIVE_PASSWORD BY 'Id81Gdac_a';
-- 授予全库权限(生产环境可缩小权限范围,仅授予martin库权限)
GRANT all ON *.* TO 'dba'@'192.168.%';
</pre></div>
<p class="maodian"><a name="_label3_2_6_13"></a></p><h4>步骤3:执行删除(不归档,仅删除)</h4>
<div class="jb51code"><pre class="brush:sql;">pt-archiver \
--source h=192.168.184.151,u=dba,p='Id81Gdac_a',D=martin,t=t2 \# 源表信息
--where "b&lt;50000" \# 删除条件
--progress 10000 \   # 每处理10000行显示进度
--limit=1000 \       # 每次处理1000行
--txn-size 10000 \   # 每10000行提交一次事务
--no-safe-auto-increment \# 不修改自增主键(避免影响后续插入)
--statistics \       # 输出统计信息(如处理时间、行数)
--purge            # 仅删除,不归档(核心参数)
</pre></div>
<p class="maodian"><a name="_label3_2_6_14"></a></p><h4>统计结果示例:</h4>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122508270251.png" /></p>
<p class="maodian"><a name="_label3"></a></p><h2>四、归档删除部分数据:先迁移再删除,兼顾数据保留与空间回收</h2>
<p>若需删除的部分数据需长期保留(如归档历史日志),需先将数据迁移到&ldquo;归档库&rdquo;,再删除源表数据。同时,需注意:<strong>delete删除后表会产生&ldquo;空洞&rdquo;(未释放的空间),需重建表回收空间</strong>。</p>
<p class="maodian"><a name="_lab2_3_7"></a></p><h3>4.1 操作步骤(用pt-archiver实现归档+删除)</h3>
<p class="maodian"><a name="_label3_3_7_15"></a></p><h4>步骤1:准备归档环境</h4>
<ul><li><strong>源库</strong>:192.168.184.151(martin库,t2表,需删除b&lt;50000的数据);</li><li><strong>归档库</strong>:192.168.184.152(新建archiver_db库,t2_archiver表,用于存储归档数据)。</li></ul>
<p class="maodian"><a name="_label3_3_7_16"></a></p><h4>步骤2:在归档库创建表结构</h4>
<div class="jb51code"><pre class="brush:sql;">-- 登录归档库(192.168.184.152)
mysql -uroot -p

-- 创建归档数据库
create database archiver_db;
use archiver_db;

-- 创建与源表结构一致的归档表
CREATE TABLE `t2_archiver` (      
`id` int NOT NULL AUTO_INCREMENT,
`a` int DEFAULT NULL,
`b` int DEFAULT NULL,
PRIMARY KEY (id),
key idx_b(b)
) ENGINE=InnoDB CHARSET=utf8mb4 ;

-- 授予dba用户归档库权限
CREATE USER 'dba'@'192.168.%' IDENTIFIED WITH MYSQL_NATIVE_PASSWORD BY 'Id81Gdac_a';
GRANT all ON *.* TO 'dba'@'192.168.%';
</pre></div>
<p class="maodian"><a name="_label3_3_7_17"></a></p><h4>步骤3:归档+删除(pt-archiver)</h4>
<div class="jb51code"><pre class="brush:sql;"># 关闭归档库的防火墙(避免连接失败)
iptables -F# 仅测试环境,生产环境需配置白名单

# 执行归档+删除
pt-archiver \
--source h=192.168.184.151,u=dba,p='Id81Gdac_a',D=martin,t=t2 \# 源表
--dest h=192.168.184.152,u=dba,p='Id81Gdac_a',D=archiver_db,t=t2_archiver \# 归档表
--where "b&lt;50000" \# 归档条件
--progress 10000 \   # 进度显示
--limit=1000 \       # 每次处理1000行
--txn-size 10000 \   # 事务大小
--no-safe-auto-increment \
--statistics \
--purge            # 归档后删除源表数据
</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122508270270.png" /></p>
<p class="maodian"><a name="_label3_3_7_18"></a></p><h4>步骤4:验证归档与删除结果</h4>
<p><strong>源库验证</strong>:</p>
<div class="jb51code"><pre class="brush:sql;">select count(*) from martin.t2 where b&lt;50000;-- 应返回0
select count(*) from martin.t2;-- 应返回50001
</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122508270261.png" /></p>
<p><strong>归档库验证</strong>:</p>
<div class="jb51code"><pre class="brush:sql;">select count(*) from archiver_db.t2_archiver;-- 应返回49999
select min(b),max(b) from archiver_db.t2_archiver;-- 应返回1和49999
</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122508270256.png" /></p>
<p class="maodian"><a name="_lab2_3_8"></a></p><h3>4.2 回收delete产生的&ldquo;空洞&rdquo;空间</h3>
<p>delete删除数据后,InnoDB会将数据标记为&ldquo;删除&rdquo;,但磁盘空间不释放(形成&ldquo;空洞&rdquo;),需通过<strong>重建表</strong>回收空间:</p>
<div class="jb51code"><pre class="brush:sql;">-- 方法1:alter table重建表(推荐,InnoDB会整理空间)
alter table martin.t2 engine=InnoDB;

-- 方法2:optimize table(效果同上,仅支持InnoDB和MyISAM)
optimize table martin.t2;

-- 验证空间变化
ll -h /data/mysql/data/martin/t2.ibd# 空间应明显减少
</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122508270287.png" /></p>
<p class="maodian"><a name="_label4"></a></p><h2>五、分区表删除:按分区清理,效率翻倍</h2>
<p>对于按时间/范围分区的表(如日志表、订单历史表),删除某一时间段的数据时,<strong>直接删除分区</strong>比delete更高效&mdash;&mdash;drop分区是DDL操作,直接删除分区对应的物理文件,无需逐行处理,速度极快。</p>
<p class="maodian"><a name="_lab2_4_9"></a></p><h3>5.1 操作步骤(以按年份分区的日志表为例)</h3>
<p class="maodian"><a name="_label3_4_9_19"></a></p><h4>步骤1:创建RANGE分区表</h4>
<div class="jb51code"><pre class="brush:sql;">use martin;

drop table if exists t3_log ;

-- 创建按年份分区的日志表(2016、2017、2018三个分区)
CREATE TABLE t3_log (
    id INT,
    log_info VARCHAR (100),-- 日志内容
    date datetime            -- 分区键(按年份分区)
) ENGINE = INNODB
PARTITION BY RANGE (YEAR(date))(-- RANGE分区,按YEAR(date)的值分区
    PARTITION p2016 VALUES less THAN (2017),-- 2016年数据(&lt;2017)
    PARTITION p2017 VALUES less THAN (2018),-- 2017年数据(&lt;2018)
    PARTITION p2018 VALUES less THAN (2019)   -- 2018年数据(&lt;2019)
);
</pre></div>
<p class="maodian"><a name="_label3_4_9_20"></a></p><h4>步骤2:插入测试数据</h4>
<div class="jb51code"><pre class="brush:sql;">insert into t3_log values
(1,'aaa','2016-01-01'),-- 进入p2016分区
(2,'bbb','2016-06-01'),-- 进入p2016分区
(3,'ccc','2017-01-01'),-- 进入p2017分区
(4,'ddd','2018-01-01');-- 进入p2018分区
</pre></div>
<p class="maodian"><a name="_label3_4_9_21"></a></p><h4>步骤3:查看分区数据分布</h4>
<div class="jb51code"><pre class="brush:sql;">select
TABLE_SCHEMA,-- 数据库名
TABLE_NAME,    -- 表名
PARTITION_NAME,-- 分区名
TABLE_ROWS   -- 分区行数
from information_schema.partitions
where table_schema='martin' and table_name='t3_log';
</pre></div>
<p style="text-align:center"><strong>结果</strong>:p2016(2行)、p2017(1行)、p2018(1行)。<br /><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122508270212.png" /></p>
<p class="maodian"><a name="_label3_4_9_22"></a></p><h4>步骤4:删除2016年数据(直接drop分区)</h4>
<div class="jb51code"><pre class="brush:sql;">-- 删除p2016分区(即删除2016年所有数据)
alter table t3_log drop partition p2016;
</pre></div>
<p class="maodian"><a name="_label3_4_9_23"></a></p><h4>步骤5:验证删除结果</h4>
<div class="jb51code"><pre class="brush:sql;">-- 查看分区列表(p2016已消失)
select PARTITION_NAME from information_schema.partitions where table_schema='martin' and table_name='t3_log';

-- 查询全表数据(2016年数据已删除)
select * from t3_log;-- 仅返回2017、2018年数据
</pre></div>
<p style="text-align:center"><img alt="" src="https://img.jbzj.com/file_images/article/202512/2025122508270218.png" /></p>
<p class="maodian"><a name="_lab2_4_10"></a></p><h3>5.2 核心优势与适用场景</h3>
<ul><li><strong>效率高</strong>:drop分区耗时毫秒级,适合TB级大表;</li><li><strong>无空洞</strong>:删除分区直接释放文件,无需后续空间回收;</li><li><strong>适用场景</strong>:按时间/范围分区的表(如日志表、账单表、订单历史表)。</li></ul>
<p class="maodian"><a name="_label5"></a></p><h2>六、总结:MySQL删除操作的核心原则与场景选型</h2>
<table><thead><tr><th>操作场景</th><th>推荐方案</th><th>核心注意事项</th></tr></thead><tbody><tr><td>删除冗余表</td><td>重命名&rarr;观察&rarr;drop</td><td>观察期1-2周,排查隐藏依赖</td></tr><tr><td>清空全表数据</td><td>truncate table</td><td>先备份,外键表需先处理关联关系</td></tr><tr><td>不归档删除部分数据(小)</td><td>循环delete + limit</td><td>每次删1000-10000行,加索引加速条件查询</td></tr><tr><td>不归档删除部分数据(大)</td><td>pt-archiver --purge</td><td>低峰期执行,避免影响业务</td></tr><tr><td>归档删除部分数据</td><td>pt-archiver --dest + 重建表</td><td>归档库与源库结构一致,删除后回收空洞空间</td></tr><tr><td>分区表删除历史数据</td><td>alter table drop partition</td><td>分区键选择合理(如时间),避免跨分区删除</td></tr></tbody></table>
<p><strong>核心原则</strong>:</p>
<ol><li><strong>安全优先</strong>:任何删除操作前必须备份,高危操作(如drop表)需先隔离观察;</li><li><strong>效率第二</strong>:根据数据量和场景选对工具,避免大事务和主从延迟;</li><li><strong>空间回收</strong>:delete后需通过重建表回收空洞,truncate/drop分区无需额外操作。</li></ol>
<p>掌握这些方法,可有效避免MySQL删除操作中的常见风险,同时兼顾效率与资源合理利用,让运维工作更稳定、高效。</p>
<p>以上就是MySQL表数据删除与清理的最佳实践的详细内容,更多关于MySQL表数据删除与清理的资料请关注琼殿技术社区其它相关文章!</p>
頁: [1]
查看完整版本: MySQL表数据删除与清理的最佳实践