首页 > 数据库 >MySQL线上环境单表1000w数据增加字段怎么做

MySQL线上环境单表1000w数据增加字段怎么做

时间:2022-10-30 13:45:56浏览次数:84  
标签:insert2 COMMENT 1000w varchar DEFAULT 单表 MySQL test NULL

向一个 1000w 数据的线上业务表里新加字段,怎么操作?

本地测试及正确解决方案:

1.准备测试环境

MySQL 测试环境

  • 系统:Linux centos 6.8
  • 内存:2G 内存
  • CPU:2 核 CPU
  • 硬盘:200G 硬盘
  • MySQL 版本:5.1
  • 测试程序:本地连内网测试

2.准备测试程序 JAVA 代码

package cn.gameboys.mysql;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;
/**
 * Description:
 *
 * @author gameboys(www.gameboys.cn)
 * @date 2019年11月28日
 */
public class InsertTest {
	public static void main(String[] args) throws ClassNotFoundException, SQLException {
		final String url = "jdbc:mysql://192.168.6.66/test3?useUnicode=true&characterEncoding=utf8";
		final String name = "com.mysql.jdbc.Driver";
		final String user = "gameboys";
		final String password = "gameboys1234";
		Connection conn = null;
		Class.forName(name); // 指定连接类型
		conn = DriverManager.getConnection(url, user, password); // 获取连接
		if (conn != null) {
			System.out.println("获取连接成功");
			insert(conn);
		} else {
			System.out.println("获取连接失败");
		}
	}
	public static void insert(Connection conn) {
		// 一共插入数据
		int totalCount = 10000000;
		// 每次sql插入数据
		int perTimeCount = 100000;
		// 开始时间
		Long begin = new Date().getTime();
		//这里换表,test_insert索引为MyISAM ,test_insert2索引为InnoDB
		//String prefix = "INSERT INTO test_insert (id,sex,name,company,department,position) VALUES ";
		String prefix = "INSERT INTO test_insert2 (id,sex,name,company,department,position) VALUES ";
		try {
			// 保存sql后缀
			StringBuffer suffix = new StringBuffer();
			// 设置事务为非自动提交
			conn.setAutoCommit(false);
			// 比起st,pst会更好些
			PreparedStatement pst = (PreparedStatement) conn.prepareStatement(""); // 准备执行语句
			// 外层循环,总提交事务次数
			for (int i = 1; i <= totalCount; i++) {
				//suffix = new StringBuffer();
				// 第j次提交步长
				// 构建SQL后缀
				suffix.append("('" + i + "','1'" + ",'我是名字" + i + "'" + ",'np公司名'" + ",'np部门'" + ",'np职位'),");
				if (i % perTimeCount == 0) {
					// 构建完整SQL
					String sql = prefix + suffix.substring(0, suffix.length() - 1);
					// 添加执行SQL
					pst.addBatch(sql);
					// 执行操作
					pst.executeBatch();
					// 提交事务
					conn.commit();
					// 清空上一次添加的数据
					suffix = new StringBuffer();
				}
			}
			// 头等连接
			pst.close();
			conn.close();
		} catch (SQLException e) {
			e.printStackTrace();
		}
		// 结束时间
		Long end = new Date().getTime();
		// 耗时
		System.out.println(totalCount + "条数据插入花费时间 : " + (end - begin) / 1000 + " s");
		System.out.println("插入完成");
	}
}

3.新建数据库,添加测试数据表:

MyISAM索引的表
CREATE TABLE `test_insert` (
  `id` int(11) NOT NULL,
  `sex` varchar(1) DEFAULT NULL COMMENT '性别',
  `name` varchar(20) DEFAULT NULL COMMENT '名字',
  `company` varchar(20) DEFAULT NULL COMMENT '公司',
  `department` varchar(20) DEFAULT NULL COMMENT '部门',
  `position` varchar(20) DEFAULT NULL COMMENT '职位',
  PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
InnoDB索引的表
CREATE TABLE `test_insert2` (
  `id` int(11) NOT NULL,
  `sex` varchar(1) DEFAULT NULL COMMENT '性别',
  `name` varchar(20) DEFAULT NULL COMMENT '名字',
  `company` varchar(20) DEFAULT NULL COMMENT '公司',
  `department` varchar(20) DEFAULT NULL COMMENT '部门',
  `position` varchar(20) DEFAULT NULL COMMENT '职位',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 

4.解决运行程序报错

com.mysql.jdbc.PacketTooBigException: Packet for query is too large (6977867 > 1048576). You can change this value on the server by setting the max_allowed_packet' variable.
mysql> show VARIABLES like '%max_allowed_packet%';
+--------------------------+------------+
| Variable_name            | Value      |
+--------------------------+------------+
| max_allowed_packet       | 1048576    |
| slave_max_allowed_packet | 1073741824 |
+--------------------------+------------+
设置插入sql的大小为100m
set global max_allowed_packet = 100*1024*1024
设置好后重新登录数据库才能看的设置后的值
mysql> show VARIABLES like '%max_allowed_packet%';
+--------------------------+------------+
| Variable_name            | Value      |
+--------------------------+------------+
| max_allowed_packet       | 104857600  |
| slave_max_allowed_packet | 1073741824 |
+--------------------------+------------+

5.执行代码得到两种引擎插入 1000w 条数据需要的时间

5.1插入表索引为MyISAM的结论:
10000000条数据插入花费时间 : 105 s
5.2插入表索引为InnoDB的结论,两次:
10000000条数据插入花费时间 : 194 s
10000000条数据插入花费时间 : 215 s

6.正确插入 1000w 数据表新加字段方法

1.新加中间表 sql

CREATE TABLE `test_insert2_new` (
  `id` int(11) NOT NULL,
  `sex` varchar(1) DEFAULT NULL COMMENT '性别',
  `name` varchar(20) DEFAULT NULL COMMENT '名字',
  `company` varchar(20) DEFAULT NULL COMMENT '公司',
  `department` varchar(20) DEFAULT NULL COMMENT '部门',
  `position` varchar(20) DEFAULT NULL COMMENT '职位',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
alter tabletest_insert2_new add `testCol` bigint(11) NOT NULL DEFAULT '0' COMMENT '测试新加字段';

2.将老表数据插入新表

insert into test_insert2_new(id, sex, name, company, department, position) select id, sex, name, company, department, position from test_insert2;

3.交换名字,添加字段成功

alter table test_insert2 rename to test_insert2_old; alter table test_insert2_new rename to test_insert2;

4.执行结果

[SQL]
insert into test_insert2_new(id, sex, name, company, department, position) select id, sex, name, company, department, position from test_insert2;
受影响的行: 10000000
时间: 66.029ms
[SQL]
alter table test_insert2 rename to test_insert2_old;
受影响的行: 0
时间: 0.058ms
[SQL]
alter table test_insert2_new rename to test_insert2;
受影响的行: 0
时间: 0.013ms
耗时为66s,期间是可以查询test_insert2表,对业务影响最小,这个方案比较可取。

8.删库跑路的操作方法:

8.1 执行 sql

alter table test_insert2_old add 'testCol' bigint(11) NOT NULL DEFAULT '0' COMMENT '测试新加字段';

8.2 结论

[SQL]
alter table test_insert2_old add `testCol` bigint(11) NOT NULL DEFAULT '0' COMMENT '测试新加字段';
受影响的行: 10000000
时间: 86.621ms
期间查询请求是可以成功的,但是update和insert是阻塞的,严重影响线上业务,所以这个方案是不可取的。

7.总结

  • MySQL 的 insert 语句后面带多个值可以加快插入速度,而且速度快到惊人;
  • MySQL 向千万级数据量的表插入新列可以采用建中间表的方式;

标签:insert2,COMMENT,1000w,varchar,DEFAULT,单表,MySQL,test,NULL
From: https://www.cnblogs.com/javaxubo/p/16841098.html

相关文章

  • mysql 通城公司灯具部数据库
    创建数据库: createdatabasetongchenggongsi;  1、           查询车间名称和电话;2、           查询属于台灯厂的车间;   3、      ......
  • 「MySQL高级篇」MySQL日志、事务原理 -- undolog、redolog、binlog、两阶段提交
    引言日志日志,在我们平时开发中主要的用途在于监控、备份,但在MySQL中,日志的功能远远不止这些,分别有用于记录的慢查询日志,回滚版本的undolog,宕机恢复的redolog、全量备份的bin......
  • 数据库定时执行sql mysql定时任务 event 执行定时任务 和sql server定时任务 作业
     本片文章目的:抛弃触发器  学会使用mysqlsqlserver  使用定时任务执行定时sql 1.sqlserver定时任务   sqlserver集成化微软开发特别的好一个结构化数......
  • MySQL系列之MySQL8.0新特性
    概述本文非原创,整理网络资源学习备用。MySQL8.0正式版8.0.11已发布,官方表示MySQL8要比MySQL5.7快2倍,还带来了大量的改进和更快的性能!注意:从MySQL5.7升级到M......
  • MySQL常用代码片段
    概述每次想要实现一个功能时,总是百度Google,挺浪费时间的,于是整理得到此文。持续更新中。字符串截取函数length​​length(str)​​:返回str的长度left​​left(str,length)......
  • MySQL timestamp(3)问题
    背景最近在负责开发维护的一款数据平台,有一个功能是把数据从某个源头数据源(如常规的JDBC数据源,MySQL,Oracle等)推到目地数据源(还包括企微,MQ等)。一次推送数据就是一个任务,当然......
  • MySQL(零)
    MySQL前置1.MySQL介绍MySQL是一个开放源代码的关系型数据库管理系统.MySQL支持大型的数据库,可以处理拥有上千万条记录的大型数据库.MySQL使用标准的sql数据语言形式.......
  • JavaWeb-MySQL基础
    JavaWeb-MySQL基础1,数据库相关概念1.1数据库存储和管理数据的仓库,数据是有组织的进行存储。数据库英文名是DataBase,简称DB。数据库就是将数据存储在硬盘上,可......
  • MySQL库表操作小结(未完成)
    MySQL库表操作小结(以下cmd都是以管理员身份运行):一、启动MySQL1、配置好环境的情况下:(注意此处的myslq80需要看自己电脑上的MySQL服务名称:可通过cmd中输入serv......
  • 查看 MySQL 数据库文件储存位置
    #1.登录MySQLmysql-uroot-pEnterpassword:***#2.输入下面命令mysql>showglobalvariableslike"%datadir%";+---------------+------------------------......