mysql 数据库表被锁住了_Mysql数据库表分区

原因
我们有一张大的数据表5000多万的数据,查询时间跨度比较大的数据的时候,比较慢。

解决办法

解决数据库性能问题方法是多种多样,在不动代码逻辑的情况下,比较节省开发成本的方式就是表分区。

实现

一般分2种方法,第一种是对现有表进行分区,第二种新创建同样字段的分区表,把老表的数据导入。

需求:按月对表分区

首先,为了方便,采用第一种对现有表进行分区。使用 Alter table (更改表)命令。

ALTER TABLE weather_dat PARTITION BY RANGE (unix_timestamp(create_time))
(   
PARTITION p0 VALUES LESS THAN (unix_timestamp('2020-02-01')),
PARTITION p1 VALUES LESS THAN (unix_timestamp('2020-03-01')), 
PARTITION p2 VALUES LESS THAN (unix_timestamp('2020-04-01')), 
PARTITION p3 VALUES LESS THAN (unix_timestamp('2020-05-01')), 
PARTITION p4 VALUES LESS THAN (unix_timestamp('2020-06-01')), 
PARTITION p5 VALUES LESS THAN (unix_timestamp('2020-07-01')), 
PARTITION p6 VALUES LESS THAN (unix_timestamp('2020-08-01')), 
PARTITION p7 VALUES LESS THAN (unix_timestamp('2020-09-01')), 
PARTITION p8 VALUES LESS THAN (unix_timestamp('2020-10-01')), 
PARTITION p9 VALUES LESS THAN (unix_timestamp('2020-11-01')), 
PARTITION p10 VALUES LESS THAN (unix_timestamp('2020-12-01')), 
PARTITION p11 VALUES LESS THAN MAXVALUE );

上面代码意思是,根据月份更改weather_da表作为分区表。Range表示是按范围分区。我现在是按数据记录创建时间作为关键字,按月进行分区。

因为create_time是timestamp类型,我们需要按时间戳进行比对,来划分数据记录应该进那个分区表。


报错:

[Err] 1503 - A PRIMARY KEY must include all columns in the table's partitioning function

意思是在表的分区函数里面,主键必须包含所有的字段。现在用到“create_time”这个字段,但它不是主键,所以报错了。

navicat调整create_time成主键。结果又报错,提示如下:

7edc929ad7067adb5c14600a0a518332.png

并且,反复几次不成功。只能决定采用第二种方式进行分区。

创建空的分区表:

CREATE TABLE `weather_dat1` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '唯一标识ID,主键',
  `road_id` int(11) DEFAULT NULL COMMENT '路段Id',
  `device_id` int(11) NOT NULL,
  `pressure` float(11,1) DEFAULT NULL COMMENT '单位毫巴hPa,1hPa=100帕斯卡',
  `atmospheric_temperature` float(11,1) DEFAULT NULL COMMENT '大气温度,单位:℃',
  `relative_humidity` int(3) DEFAULT NULL COMMENT '相对湿度,单位:%,如85表示相对湿度85%',
  `dew_point_temperature` float(11,1) DEFAULT NULL COMMENT '露点温度,单位:℃,有的有输出,有的需根据温湿度计算',
  `wind_speed` float(11,1) DEFAULT NULL COMMENT 'm/s',
  `wind_direction` int(11) DEFAULT NULL COMMENT '风向,360° ',
  `precipitation` float(11,1) DEFAULT NULL COMMENT '降水量,单位:mm/min,表示每分钟的mm降水量',
  `visibility` int(11) DEFAULT NULL COMMENT '能见度,单位:m',
  `weather_phenomena` varchar(255) DEFAULT NULL COMMENT '天气现象,取决于天气现象传感器的输出',
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '精确到分钟,即每分钟一条记录,如“201905202310”',
  PRIMARY KEY (`id`,`create_time`) USING BTREE,
  KEY `idx_weatherDat_deviceIdCreateTime` (`device_id`,`create_time`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=118196010 DEFAULT CHARSET=utf8 ROW_FORMAT=COMPACT
PARTITION BY RANGE (unix_timestamp(create_time))
(PARTITION p0 VALUES LESS THAN (1580486400) ENGINE = InnoDB,
 PARTITION p1 VALUES LESS THAN (1582992000) ENGINE = InnoDB,
 PARTITION p2 VALUES LESS THAN (1585670400) ENGINE = InnoDB,
 PARTITION p3 VALUES LESS THAN (1588262400) ENGINE = InnoDB,
 PARTITION p4 VALUES LESS THAN (1590940800) ENGINE = InnoDB,
 PARTITION p5 VALUES LESS THAN (1593532800) ENGINE = InnoDB,
 PARTITION p6 VALUES LESS THAN (1596211200) ENGINE = InnoDB,
 PARTITION p7 VALUES LESS THAN (1598889600) ENGINE = InnoDB,
 PARTITION p8 VALUES LESS THAN (1601481600) ENGINE = InnoDB,
 PARTITION p9 VALUES LESS THAN (1604160000) ENGINE = InnoDB,
 PARTITION p10 VALUES LESS THAN (1606752000) ENGINE = InnoDB,
 PARTITION p11 VALUES LESS THAN MAXVALUE ENGINE = InnoDB);

老表数据导入到新表SQL语句:

insert into weather_dat1  SELECT * FROM weather_dat

5000万数据挂机一个晚上导入成功。导入成功后,把分区表命名weather_dat。

总结:对大数据表直接进行更改为分区表失败的概率很大,可能是因为数据量太大的原因。建议采用新建同字段的分区表,再把数据导入。

另外,关于现在分区表按日期是hardcode了,如果超出分区的时间,表又需要重新分区。如何自动创建分区表是可以探索下一个话题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值