线上MySQL某个历史数据表的分区笔记

背景:

线上的一个历史数据库,业务方反馈经常遇到一个范围查询就导致CPU迅速飙升的情况。拿到他们提供的SQL后,SQL类似下面这种:

select * from `order_his` where `xxxx` = ‘222‘ AND `XXXX` <> 1 AND order_time > ‘2016-11-01 00:00:00‘ AND order_time < ‘2017-06-01 00:00:00‘ \G

explain看了下发现基本上是全表扫描了,效率太低了,并且他们都是按月查询的,因此我们就对这张表按月进行分区,就能大大减少扫描的行数。

注意:TIMESTAMP类型的列,只能基于UNIX_TIMESTAMP函数进行分区,切记!

### 原始order_his表类似如下这种结构:

CREATE TABLE `order_his` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`order_time` timestamp NULL DEFAULT NULL,

`pay_time` timestamp NULL DEFAULT NULL,

`create_time` timestamp NULL DEFAULT NULL,

`update_time` timestamp NULL DEFAULT NULL,

PRIMARY KEY (`id`),

) ENGINE=InnoDB AUTO_INCREMENT=47603581 DEFAULT CHARSET=utf8;

step0 创建一个表结构和原先的表一样的tmp表

create table `order_his_tmp` like `order_his`;

step1  修改原有的主键,将分区键添加到主键里。

alter table `order_his_tmp` drop primary key,add primary key(id,order_time);

必须把分区键加到主键里面,不然step2也会报错提醒你这样做的。

step2 分区操作

ALTER TABLE `order_his_tmp` PARTITION BY RANGE (UNIX_TIMESTAMP (order_time))

(

PARTITION  P201601  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2016-02-01‘)) ,

PARTITION  P201602  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2016-03-01‘)) ,

PARTITION  P201603  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2016-04-01‘)) ,

PARTITION  P201604  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2016-05-01‘)) ,

PARTITION  P201605  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2016-06-01‘)) ,

PARTITION  P201606  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2016-07-01‘)) ,

PARTITION  P201607  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2016-08-01‘)) ,

PARTITION  P201608  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2016-09-01‘)) ,

PARTITION  P201609  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2016-10-01‘)) ,

PARTITION  P201610  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2016-11-01‘)) ,

PARTITION  P201611  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2016-12-01‘)) ,

PARTITION  P201612  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2017-01-01‘)) ,

PARTITION  P201701  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2017-02-01‘)) ,

PARTITION  P201702  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2017-03-01‘)) ,

PARTITION  P201703  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2017-04-01‘)) ,

PARTITION  P201704  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2017-05-01‘)) ,

PARTITION  P201705  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2017-06-01‘)) ,

PARTITION  P201706  VALUES LESS THAN  (UNIX_TIMESTAMP(‘2017-07-01‘))

);

step3、将原先表的数据灌入新的tmp表

insert into `order_his_tmp` select * from `order_his`;

step4、查询验证

explain partitions select * from `order_his_tmp` where `xxxx` = ‘222‘ AND `XXXX` <> 1 AND order_time > ‘2015-11-01 00:00:00‘ AND order_time < ‘2015-12-21 00:00:00‘ \G

*************************** 1. row ***************************

id: 1

select_type: SIMPLE

table: order_his

partitions: p201511,p201512   ### 可以看到这里走的是2015年11和12月,这2个分区

...........部分内容省略.............

注意: 当时在线上操作的时候,发现即使做了分区,执行计划里面显示的还是ALL全表扫描了,于是根据这个SELECT 加了个索引解决了这个问题。这里没有真实环境不好贴图出来。

step5、替换原先的表

通知开发同学当前不要对`order_his`表执行查询操作。

然后我们执行:

rename table `order_his` `order_his_nopart`;

rename table `order_his_tmp` `order_his`;

这样的话,新的`order_his`表就是分区表啦。

step6、添加分区表

后期如果需要加分区的话,只要执行如下这种操作就可以添加一个新的分区

ALTER TABLE `order_his` ADD PARTITION ( PARTITION P201707 VALUES LESS THAN (UNIX_TIMESTAMP(‘2017-08-01‘))) ;

当然,如果我们想省事的话,就在step2的时候,一次性多创建很多分区(我当时是按月建分区,一直创建到2019年)

此外,也可以写个存储过程配合event_schedule每月自动创建一个新的分区。

使用存储过程的方法这里先略过,后期补充。

时间: 2024-10-06 17:21:33

线上MySQL某个历史数据表的分区笔记的相关文章

如何有效的跟踪线上 MySQL 实例表和权限的变更

介绍 从系统管理员或 DBA 的角度来讲, 总期望将线上的各种变更限制在一个可控的范围内, 减少一些不确定的因素. 这样做有几点好处: 1. 记录线上的库表变更; 2. 对线上的库表变更有全局的了解; 3. 如果有问题, 方便回滚操作; 从这三点来看, 有很多种方式可以实现, 比如通过 migrate 等工具强制所有的操作都以统一的方式执行, 这需要开发人员做更多的配合, 所以这类工具在非规模话的业务场景中较难实现; 另外管理员或 DBA 也可以通过知识库比如 redmine 等类似的方式记录变

MySQL的分表和分区介绍

在日常开发或维护中经常会遇到大表的情况,所谓的大表是指存储了百万级乃至千万级条记录的表.这样的表过于庞大,导致数据库在查询和插入的时候耗时太长,性能低下,如果涉及联合查询的情况,性能会更加糟糕.分表和表分区的目的就是减少数据库的负担,提高数据库的效率,通常点来讲就是提高表的增删改查效率. 一.什么是分表: 分表是将一个大表按照一定的规则分解成多张具有独立存储空间的实体表,我们可以称为子表,每个表都对应三个文件,MYD数据文件,.MYI索引文件,.frm表结构文件.这些子表可以分布在同一块磁盘上,

线上mysql内存持续增长直至内存溢出被killed分析

来新公司前,领导就说了,线上生产环境Mysql库经常会发生日间内存爆掉被killed的情况,结果来到这第一天,第一件事就是要根据线上服务器配置优化配置,同时必须找出现在mysql内存持续增加爆掉的原因,虽然我主业已经不是数据库更不是dba了. 这个业务上基本山算是OLTP,盘中都是很简单的SQL,所以性能上虽然有些SQL有些慢,但看过slow-log和performance_schema,可以忽略不计. 初步了解,应用是java开发的,但是应用端没有出现过OOM的情况,也不见卡死或者越来越慢的情

线上MYSQL同步报错故障处理总结(转)

前言 在发生故障切换后,经常遇到的问题就是同步报错,数据库很小的时候,dump完再导入很简单就处理好了,但线上的数据库都150G-200G,如果用单纯的这种方法,成本太高,故经过一段时间的摸索,总结了几种处理方法. 生产环境架构图 目前现网的架构,保存着两份数据,通过异步复制做的高可用集群,两台机器提供对外服务.在发生故障时,切换到slave上,并将其变成master,坏掉的机器反向同步新的master,在处理故障时,遇到最多的就是主从报错.下面是我收录下来的报错信息. 常见错误 最常见的3种情

记一次线上MySQL数据库死锁问题

最近线上项目报了一个MySQL死锁(DealLock)错误,虽说对业务上是没有什么影响的,由于自己对数据库锁这块了解不是很多,之前也没怎么的在线上碰到过.这次刚好遇到了,便在此记录一下. 出现死锁问题背景 项目层面:报错的项目做的是一个批量下单的动作,会同时写入多条订单数据,代码之前写的是一个事务中一个循环一条一条insert到数据库(至于为啥没用批量插入就不追究了,历史原因了). 数据库层面:一张test表(非线上真实表),比较重要的是有一个 type 和 name的唯一索引. 事务隔离级别:

记一次线上mysql主从架构异常的恢复经历

前提:之前一位同事负责的一位客户,因后期转到devops小组.所以将此用户交接给我,在后期发现有一套数据库主从环境,从库已经无法正常使用.查看slave 状态为: 其中:Master_Log_File:#此处显示的bin-log已经在master上找不见了Read_Master_Log_Pos:#显示的行数也就存在没有意义了Slave_IO_Running:NO #salve io进程显示为no,无法从master同步数据因此判定从库已经无法使用,需要及时修复.保证主从架构正常使用. 以下是恢复

MySql分库分表与分区的区别和思考

一.分分合合 说过很多次,不要拘泥于某一个技术的一点,技术是相通的.重要的是编程思想,思想是最重要的.当数据量大的时候,需要具有分的思想去细化粒度.当数据量太碎片的时候,需要具有合的思想来粗化粒度. 1.1 分 很多技术都运用了分的编程思想,这里来举几个例子,这些都是分的思想 集中式服务发展到分布式服务 从Collections.synchronizedMap(x)到1.7ConcurrentHashMap再到1.8ConcurrentHashMap,细化锁的粒度的同时依旧保证线程安全 从Ato

一则线上MySql连接异常的排查过程

Mysql作为一个常用数据库,在互联网系统应用很多.有些故障是其自身的bug,有些则不是,这里以前段时间遇到的问题举例. 问题 当时遇到的症状是这样的,我们的应用在线上测试环境,JMeter测试过程中,发现每次压力测试开始时访问低前几个http request请求会超时,而之后的请求持续测试中都不会.最后一点是Tomcat的log并没有报什么错误. 压测的内容就是起200线程不停的向这个http页面发送请求,这个页面逻辑也比较简单,会在后端向数据库插入一条数据,连接池采用阿里的Druid(这个坑

线上Linux服务器(2TB)分区参考方案

如果是线上服务器,假设它是 2TB 的 SATA 硬盘.8GB 内存,建议按如下方式进行分区: / 20480M /boot 128M swap 10240M /data 2016152M(即剩余的所有磁盘空间) 如果是 个人电脑 学习用,假设虚拟机的硬盘定为 10GB,分区参考如下: / 2048M /boot 128M swap 512M /data 7552M(即剩余的所有硬盘空间)