一则清理MySQL大表以释放磁盘空间的案例

一、基本情况:
1.dbtest库554G,先清理st_online_time_away_ds(37G)表的数据,保留半年的数据:
1)删除的数据:select count(1),tdate from dbtest.st_online_time_away_ds where tdate < '2017-08-01';(记录数为:462171894)
2)保留的数据:select count(1),tdate from dbtest.st_online_time_away_ds where tdate >= '2017-08-01';(记录数为:264870859)
2.59.38.194.32机器磁盘剩余空间120G。
3.业务是离线的定时任务,不是实时的。
4.delete部分数据需要带where条件,此操作不会释放磁盘空间,truncate会释放空间。
二、处理方案:
1.方案一:评估先delete操作然后再使用optimize优化表可能耗时过长,并且释放的磁盘空间可能不理想。不推荐使用。
2.方案二:先delete半年前的数据,然后dump整个表(给表加锁,防止写入操作),再truncate表释放磁盘空间,然后load数据。数据量不大的时候可以使用。
以下是各个部分操作的预估时间:
1)删除半年以前的数据(大概需要10分钟):
mysql>delete from dbtest.st_online_time_away_ds where tdate < '2017-08-01';
注意:数据量有462171894条记录,需要确保where条件中tdate字段有索引,否则删除操作时间很长而且扫描大表很耗资源。
2)dump数据(以50M/s的速度来计算,大概需要10分钟):
/data/app/mysql/bin/mysqldump -S /data/db/mysql/mysql_3306.sock -uroot -p --lock-tables --databases dbtest --tables st_online_time_away_ds > /data/st_online_time_away_ds_bak.sql
3)删除st_online_time_away_ds表释放空间(大概需要5分钟):
mysql>truncate table dbtest.st_online_time_away_ds;
4)load数据(load数据的时间大概是dump的10倍,大概需要100分钟):
mysql>load data infile "/data/st_online_time_away_ds_bak.sql" into table dbtest.st_online_time_away_ds;

/data/app/mysql/bin/mysql -S /data/db/mysql/mysql_3306.sock -uroot -p < /data/st_online_time_away_ds_bak.sql
5)验证数据的可用性,删除dump的/data/st_online_time_away_ds_bak.sql文件。
3.方案三:为不影响生产的写,现改成以下步骤:
1)将当前生产表改名临时表
2)重新建立一张新的生产表,生产可直接写入数据,新建表时AUTO_INCREMENT会初始化一个较大值
3)从临时表查询符合条件的数据写回信的生产表
4)如果没有问题,则临时表可以删掉,否则进行回滚。
以下是具体执行的sql:
use dbtest;
-- 1、先将表更名
rename table dbtest.stat_server_online_67 to dbtest.stat_server_online_67_temp;
-- 2、 重新建一张正式表 , 生产可直接写进去
CREATE TABLE dbtest.`stat_server_online_67` (
`auto_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '自增ID',
`server_id` int(11) NOT NULL COMMENT '服务器ID',
`stat_type` tinyint(4) NOT NULL COMMENT '采集类型, 1:在线;2:注册',
`stat_time` datetime NOT NULL COMMENT '采集时间',
`value` int(11) NOT NULL COMMENT '采集结果',
`top` int(11) NOT NULL DEFAULT '0' COMMENT '当天最高在线',
`low` int(11) NOT NULL DEFAULT '0' COMMENT '当天最低在线',
`game_id` int(11) NOT NULL COMMENT '游戏ID',
`platform_id` int(11) NOT NULL COMMENT '平台ID',
`create_time` datetime NOT NULL COMMENT '创建时间',
`system_platform` varchar(30) NOT NULL DEFAULT '' COMMENT '系统平台',
`language_country` varchar(30) NOT NULL DEFAULT '' COMMENT '语言国别',
PRIMARY KEY (`auto_id`),
UNIQUE KEY `AK_Key_serverId_statType_statTime_sPlatform_lCountry` (`server_id`,`stat_type`,`stat_time`,`system_platform`,`language_country`),
KEY `AK_Key_statTime_gameId_PlatformId` (`stat_time`,`game_id`,`platform_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1168939988 DEFAULT CHARSET=utf8 COMMENT='服务器在线/注册统计';
-- 3、将保留数据保存到新表上
insert into dbtest.stat_server_online_67 select * from dbtest.stat_server_online_67_temp where stat_time >= '2015-10-27 10:00:00' and stat_time <= '2018-02-07 00:00:00' and game_id=67 and platform_id in (1,34,76,211,229,415,466);
-- 4、清除旧表数据
drop table dbtest.stat_server_online_67_temp;
-- 5、回滚
-- rename table dbtest.stat_server_online_67 to dbtest.stat_server_online_67_useless;
-- rename table dbtest.stat_server_online_67_temp to dbtest.stat_server_online_67;
4.方案四:如果表的数据量很大,方案三中执行第三步耗时较长,影响线上数据写入,还需优化下。
如:stat_server_online_61表数据量比较大,已超过100G,为不影响线上写入,执行步骤改成如下:
use dbtest;
-- 1、先将表更名
rename table dbtest.stat_server_online_61 to dbtest.stat_server_online_61_temp;
-- 2、 重新建一张正式表 , 生产可直接写进去
CREATE TABLE dbtest.`stat_server_online_61` like dbtest.stat_server_online_61_temp;
-- 3、新建一张中间表,中间表保存历史数据
CREATE TABLE dbtest.`stat_server_online_61_2` like dbtest.stat_server_online_61_temp;
-- 4、将保留数据保存到中间表上
insert into dbtest.stat_server_online_61_2 (server_id,stat_type,stat_time,value,top,low,game_id,platform_id,create_time,system_platform,language_country)
select server_id,stat_type,stat_time,value,top,low,game_id,platform_id,create_time,system_platform,language_country from dbtest.stat_server_online_61_temp where stat_time <= '2018-02-07 00:00:00' and game_id=61 and platform_id in (1,28,34,37,40,52,64,76,160,163,166,199,211,229,235,247,265,271,283,286,373,415,451,466,478,484,499,505,568,577,697,925,997,1072,1081,1126,1162,1198);
这一步遇到的问题和处理方式:由于这一步的操作涉及的数据量太大,导致在/tmp目录下的临时文件太大(可以使用#lsof | grep delete可以查看到mysql进程占用的未释放的文件,注意不能kill掉这些文件的PID,否则会导致kill掉mysql进程,需要查看进程评估之后再决定是否需要重启),占用/根目录空间造成根目录满而操作中止,影响数据库实例和服务器的使用,此时通过#show processlists;#kill [insert进程id];无法kill掉进程。只能重启mysql实例以释放空间。重启mysql之后使用#show variables like "%tmp%";查看tmpdir=/tmp;修改这个路径到非根目录的其他足够空间的目录再执行以上insert操作即可。
-- 5、把生产表改成临时表
rename table dbtest.stat_server_online_61 to dbtest.stat_server_online_61_temp_2;
-- 6、将中间表改成正式表
rename table dbtest.stat_server_online_61_2 to dbtest.stat_server_online_61;
-- 7、将临时表数据写回正式表(少量数据)
insert into dbtest.stat_server_online_61 (server_id,stat_type,stat_time,value,top,low,game_id,platform_id,create_time,system_platform,language_country)
select server_id,stat_type,stat_time,value,top,low,game_id,platform_id,create_time,system_platform,language_country from dbtest.stat_server_online_61_temp_2
-- 8 清除旧表数据
drop table dbtest.stat_server_online_61_temp;
drop table dbtest.stat_server_online_61_temp_2;

  

[记录]一则清理MySQL大表以释放磁盘空间的案例的更多相关文章

  1. Tomcat清理日志文件无法立即释放磁盘空间

    1 自己删除了Tomcat的日志文件,但是依然显示磁盘百分百占用 进入Tomcat目录显示日志已经删除 查询磁盘空间依旧百分百占用 2 自己杀死Tomcat进程然后重启,成功释放空间 3 原因,通过网 ...

  2. IEE重建表完全释放磁盘空间具体步骤参考

    环境:RHEL 5.3 + IEE 5.1.40 本文目的:指导项目侧人员再遇到此类改动需求时可以自己更改.需求:mr_intrainterfreq表重建,历史数据全部删掉. 1.停库: 1.1确认现 ...

  3. 【原创】记一次MySQL大表高并发写入引发CPU飙升的排障过程

    目录 一.故障现象... 1 二.初步分析... 2 三.排障过程... 2 1.排查是否QPS或insert并发请求上升导致问题发生... 2 2.排查是否锁资源等待或block导致了insert变 ...

  4. 优秀后端架构师必会知识:史上最全MySQL大表优化方案总结

    本文原作者“ manong”,原创发表于segmentfault,原文链接:segmentfault.com/a/1190000006158186 1.引言   MySQL作为开源技术的代表作之一,是 ...

  5. MySQL 大表优化方案(长文)

    当MySQL单表记录数过大时,增删改查性能都会急剧下降,可以参考以下步骤来优化: 单表优化 除非单表数据未来会一直不断上涨,否则不要一开始就考虑拆分,拆分会带来逻辑.部署.运维的各种复杂度,一般以整型 ...

  6. 从云数据迁移服务看MySQL大表抽取模式

    摘要:MySQL JDBC抽取到底应该采用什么样的方式,且听小编给你娓娓道来. 小编最近在云上的一个迁移项目中被MySQL抽取模式折磨的很惨.一开始爆内存被客户怼,再后来迁移效率低下再被怼.MySQL ...

  7. (转) Delete/Truncate删除,释放表空间、降低高水位线、resize释放磁盘空间相关优化

    硬盘空间不足,打算删除数据库中的多余数据,但删除数据后,硬盘硬盘空间不能释放.[delete后用:alter table table_name move    truncate后用:alter tab ...

  8. MySQL删除数据几种情况以及是否释放磁盘空间【转】

    MySQL删除数据几种情况以及是否释放磁盘空间: 1.drop table table_name 立刻释放磁盘空间 ,不管是 Innodb和MyISAM ; 2.truncate table tabl ...

  9. Mysql InnoDB彻底释放磁盘空间

    Innodb数据库对于已经删除的数据只是标记为删除,并不真正释放所占用的磁盘空间,这就导致InnoDB数据库文件不断增长. 如果需要彻底释放磁盘空间,则需要先导出数据,然后删除数据文件,最后导入数据. ...

随机推荐

  1. 解决svn--Unable to connect to a repository at URL ‘https://xxxxxx’ 问题

    在checkout项目时,出现如下错误: Error  Unable to connect to a repository at URL 'https://XXXX' Error  Access to ...

  2. [转]同一台Windows机器中启动多个Memcached服务

    Memcached的安装后,如果手头上只有一台机器,又想做多节点测试咋办? 这就需要在一台机器上启动多个Memcached服务了. 假设Memcached在如下目录:C:\memcached\memc ...

  3. linux_操作系统

    如何查询操作系统版本? cat /etc/redhat-release 什么是操作系统? -- win10,linux都是os,应用软件和硬件打交道中间桥梁软件,管理 硬件+软件 资源,计算机系统基础 ...

  4. 前后端分离之CORS和WebApi

    目前的项目是前端mv*+api的方式进行开发的,以前都是没有跨域的方案,前后端人员在同一个解决方案里边进行开发,前端人员要用IIS或VS来开发和调试Api,这样就很不方便,迫切需要跨域访问Api. 评 ...

  5. GIT工程迁移方法总结

    Git工程迁移方法总结 Git最近准备迁移一下位置,这里采用命令行的方式,做如下操作. 1.git init  初始化git仓库,这个时候发现本地文件夹多了个.git的文件夹. 2.git remot ...

  6. Shader 入门笔记(二) CPU和GPU之间的通信

    渲染流水线的起点是CPU,即应用阶段. 1)把数据加载到显存中 2)设置渲染状态,通俗说这些状态定义了场景中的网格是怎样被渲染的. 3)调用DrawCall,一个命令,CPU通知GPU.(这个命令仅仅 ...

  7. 【转】centos安装vim7.4

    centos安装vim7.4   系统版本centos6.4; root权限 su - root     卸载 $ rpm -qa | grep vim $ yum remove vim vim-en ...

  8. sqlserver数据库使用技巧(一)--限制数据库的大小

    如何限制数据库的大小? 随着数据库的使用,他占用的空间会越来越大,为了便于资源的合理分配和管理,我们可以限制其最大的大小,这个建议只在测试环境使用 具体操作如下: 打开sqlserver数据库管理工具 ...

  9. traffic server文件目录

    功能: Trafficserver的主要功能是缓存,当然你也可以用它来做纯粹的反向代理(像通常用nginx那样).通常切入一个庞大的系统的最好方式是看如何使用,使用traffic server的主要入 ...

  10. left join on/right join on/inner join on/full join on连接

    现在有两张表,第一张表是用户表,第二张表是订单表.情况是这样的,在我这张用户表里用户很多,但是真正下单的人却不多,而且,每一个用户可以有多个订单.然后领导喊话了,小王,你给我查下,现在咱们的订单有多少 ...