在Oracle中快速创建一张百万级别的表,一张十万级别的表 并修改两表中1%的数据 全部运行时间66秒
万以下小表做性能优化没有多大意义,因此我需要创建大表;
创建大表有三种方法,一种是insert into table selec..connect by.的方式,它最快但是数据要么是连续值,要么是随机值或是系统值,并不好用,而且总量上受到限制;另一种方法是用程序,借助Oracle的批量插值语法插入数据,它好在数据可以用程序掌控,总量也没有限制,缺点是速度慢;还有一种方法是有一张大表,把它的数据倒腾进来,语法是 insert into newtable select * from oldtable,这种方法暂时不在我的考虑之列。
为了节约时间,我采用了两种结合的办法,即用第一种方式先大量建立数据,再用程序修改其中一部分。
下面进入正题:
百万级别的表建表语句是这样的:
CREATE TABLE bigtable
(
id NUMBER not null primary key,
name NVARCHAR2(60) not null,
score NUMBER(4,0) NOT NULL,
createtime TIMESTAMP (6) not null
)
给它塞入百万数据可以这样做:
Insert into bigtable
select rownum,dbms_random.string('*',dbms_random.value(6,20)),dbms_random.value(0,20),sysdate from dual
connect by level<=1000000
order by dbms_random.random
使用上面这个方法,在我的T440p机器上实验,一次性创建的记录数大约在两百万到三百万之间,再多就会报“
第 1 行出现错误:
ORA-30009: CONNECT BY 操作内存不足
”看来机器性能在制约我的研究。
看看它的运行数据如何:
已创建1000000行。 已用时间: 00: 00: 39.87
近四十秒创建百万数据,还不错。
十万级别的表结构如下:
create table smalltable
(
id NUMBER not null primary key,
name NVARCHAR2(60) not null,
createtime TIMESTAMP (6) not null
)
同样的方式给它塞入数据:
Insert into smalltable
select rownum,dbms_random.string('*',dbms_random.value(6,20)),sysdate from dual
connect by level<=100000
order by dbms_random.random
发现4秒不到就搞定了:
已创建100000行。 已用时间: 00: 00: 03.71
当然这样的数据还不够,于是下面的程序登场了,它的作用是将某表中百分之一记录的name字段改写成设定数组中的随机值:
package com.ufo;
public class DBParam {
public final static String Driver = "oracle.jdbc.driver.OracleDriver";
public final static String DbUrl = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
public final static String User = "ufo";
public final static String Pswd = "1234";
}
package com.ufo.bigsmall; import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.DecimalFormat;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet; import com.ufo.DBParam; public class RecordChanger {
public boolean changeOnePencent(String table) {
Connection conn = null;
Statement stmt = null; try{
Class.forName(DBParam.Driver).newInstance();
conn = DriverManager.getConnection(DBParam.DbUrl, DBParam.User, DBParam.Pswd);
stmt = conn.createStatement(); long startMs = System.currentTimeMillis(); int totalCount=fetchExistCount(table,stmt);
System.out.println("There are "+toEastNumFormat(totalCount)+" records in the table:'"+table+"'."); int changeCount=totalCount/100;
System.out.println("There are "+toEastNumFormat(changeCount)+" records should be changed."); Set<Integer> idSet=fetchIdSet(totalCount,changeCount,table,stmt);
System.out.println("There are "+toEastNumFormat(idSet.size())+" records in idSet."); int changed=updateRecords(idSet,table,stmt);
System.out.println("There are "+toEastNumFormat(changed)+" records have been changed."); long endMs = System.currentTimeMillis();
System.out.println("It takes "+ms2DHMS(startMs,endMs)+" to update 1% records of table:'"+table+"'.");
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
stmt.close();
conn.close();
} catch (SQLException e) {
System.out.print("Can't close stmt/conn because of " + e.getMessage());
}
} return false;
} private int updateRecords(Set<Integer> idSet,String tableName,Statement stmt) throws SQLException{
int updated=0; for(int id:idSet) {
String sql="update "+tableName+" set name='"+getRNDName()+"' where id='"+id+"' ";
updated+= stmt.executeUpdate(sql);
} return updated;
} private String getRNDName() {
String[] arr= {"Andy","Bill","Cindy","张三","张飞","张好古","李四","王五","赵六","孙七","钱八","岳飞","关羽","刘备","曹操","张辽","虚竹","王语嫣"};
int index=getRandom(0,arr.length);
return arr[index];
} // fetch a set of id which should be changed
private Set<Integer> fetchIdSet(int totalCount,int changeCount,String tableName,Statement stmt) throws SQLException{
Set<Integer> idSet=new TreeSet<Integer>(); while(idSet.size()<changeCount) {
int id=getRandom(0,totalCount);
if(idSet.contains(id)==false && isIdExist(id,tableName,stmt)) {
idSet.add(id);
}
} return idSet;
} private boolean isIdExist(int id,String tableName,Statement stmt) throws SQLException{
String sql="select count(*) as cnt from "+tableName+" where id='"+id+"' "; ResultSet rs = stmt.executeQuery(sql); while (rs.next()) {
int cnt = rs.getInt("cnt");
return cnt==1;
} rs.close();
return false;
} // get a random num between min and max
private static int getRandom(int min, int max){
Random random = new Random();
int s = random.nextInt(max) % (max - min + 1) + min;
return s;
} // fetch exist record count of a table
private int fetchExistCount(String tableName,Statement stmt) throws SQLException{
String sql="select count(*) as cnt from "+tableName+""; ResultSet rs = stmt.executeQuery(sql); while (rs.next()) {
int cnt = rs.getInt("cnt");
return cnt;
} rs.close();
return 0;
} // 将整数在万分位以逗号分隔表示
public static String toEastNumFormat(long number) {
DecimalFormat df = new DecimalFormat("#,####");
return df.format(number);
} // change seconds to DayHourMinuteSecond format
private static String ms2DHMS(long startMs, long endMs) {
String retval = null;
long secondCount = (endMs - startMs) / 1000;
String ms = (endMs - startMs) % 1000 + "ms"; long days = secondCount / (60 * 60 * 24);
long hours = (secondCount % (60 * 60 * 24)) / (60 * 60);
long minutes = (secondCount % (60 * 60)) / 60;
long seconds = secondCount % 60; if (days > 0) {
retval = days + "d" + hours + "h" + minutes + "m" + seconds + "s";
} else if (hours > 0) {
retval = hours + "h" + minutes + "m" + seconds + "s";
} else if (minutes > 0) {
retval = minutes + "m" + seconds + "s";
} else {
retval = seconds + "s";
} return retval + ms;
} public static void main(String[] args) {
RecordChanger rc=new RecordChanger();
rc.changeOnePencent("bigtable");
}
}
以下是修改两个表的运行结果反馈:
There are 10,0000 records in the table:'smalltable'.
There are 1000 records should be changed.
There are 1000 records in idSet.
There are 1000 records have been changed.
It takes 2s276ms to update 1% records of table:'smalltable'. There are 100,0000 records in the table:'bigtable'.
There are 1,0000 records should be changed.
There are 1,0000 records in idSet.
There are 1,0000 records have been changed.
It takes 20s251ms to update 1% records of table:'bigtable'.
全部运行时间加起来一分钟出点头,还是可以的。
--END-- 2020年1月5日09点32分
在Oracle中快速创建一张百万级别的表,一张十万级别的表 并修改两表中1%的数据 全部运行时间66秒的更多相关文章
- 教你几招,快速创建 MySQL 五百万级数据,愉快的学习各种优化技巧
我是风筝,公众号「古时的风筝」,一个兼具深度与广度的程序员鼓励师,一个本打算写诗却写起了代码的田园码农! 文章会收录在 JavaNewBee 中,更有 Java 后端知识图谱,从小白到大牛要走的路都在 ...
- 在.NET中快速创建一个5GB、10GB或更大的空文件
对于通过UDP进行打文件传输的朋友应该首先会考虑到一个问题,那就是由于UDP并不会根据先来先到原则进行发送,也许你发送端发送的时候是以包1和包2的顺序传输的,但接收端可能以包2和包1 的顺序来进行接收 ...
- 在docker中快速创建包含ip相关tool的ubuntu镜像
在docker学习中需要创建轻量级的,包含ip相关工具的容器,支持ping,ip,ethtool,brctrl等相关指令. 下面就是快速创建一个满足需求的ubunut镜像的过程: 1) 在docker ...
- Visual Studio 中快速创建方法 Generate a method in Visual Studio
2020-04-04 https://docs.microsoft.com/en-us/visualstudio/ide/reference/generate-method?view=vs-2019 ...
- OC中快速创建NSNumber NSDictionary NSArray的方法
NSNumber: @() @小括号 或者 NSNumber * num = @3; NSValue * value = @4; NSDictionary :@{} @大括 ...
- 开箱即用 yyg-cli(脚手架工具):快速创建 vue3 组件库和vue3 全家桶项目
1 yyg-cli 是什么 yyg-cli 是优雅哥开发的快速创建 vue3 项目的脚手架.在 npm 上发布了两个月,11月1日进行了大升级,发布 1.1.0 版本:支持创建 vue3 全家桶项目和 ...
- oracle 如何快速删除两表非关联数据(脏数据)?
1.情景展示 现在有两者表,表1中的主键id字段和表2的index_id相对应.如何删除两表非关联数据? 2.解决方案 --第1步 delete from VIRTUAL_CARD t where ...
- mysql 百万级数据库优化方案
https://blog.csdn.net/Kaitiren/article/details/80307828 一.百万级数据库优化方案 1.对查询进行优化,要尽量避免全表扫描,首先应考虑在 wher ...
- mysql 百万级查询优化
关于mysql处理百万级以上的数据时如何提高其查询速度的方法 最近一段时间由于工作需要,开始关注针对Mysql数据库的select查询语句的相关优化方法. 由于在参与的实际项目中发现当mysql表的数 ...
随机推荐
- SpringBoot常用配置,引入外部配置文件信息,热加载
SpringBoot的配置文件格式 yml规范 SpringBoot的配置文件支持properties和yml,甚至还支持json. 更推荐使用yml文件格式: yml文件,会根据换行和缩进帮助咱们管 ...
- C#LeetCode刷题-回溯算法
回溯算法篇 # 题名 刷题 通过率 难度 10 正则表达式匹配 18.8% 困难 17 电话号码的字母组合 43.8% 中等 22 括号生成 64.9% 中等 37 解数独 45.8% ...
- Homekit_温湿度_人体红外_光强_传感器
市面上大多数,传感器产品多是简单的单个传感器进行售卖,这里我推荐一款四合一的产品,使用Homekit进行控制. 前置需求: 苹果手机一台 四合一传感器一个 USB数据线一根 介绍: 1.外观上是一个小 ...
- 【小白学AI】随机森林 全解 (从bagging到variance)
文章转自公众号[机器学习炼丹术],关注回复"炼丹"即可获得海量免费学习资料哦! 目录 1 随机森林 2 bagging 3 神秘的63.2% 4 随机森林 vs bagging 5 ...
- Linux C++实现一服务器与多客户端之间的通信
通过网络查找资料得到的都是一些零碎不成体系的知识点,无法融会贯通.而且需要筛选有用的信息,这需要花费大量的时间.所以把写代码过程中用到的相关知识的博客链接附在用到的位置,方便回顾. 1.程序流程 服务 ...
- Jmeter 常用函数(10)- 详解 __threadNum
如果你想查看更多 Jmeter 常用函数可以在这篇文章找找哦 https://www.cnblogs.com/poloyy/p/13291704.html 作用 返回当前线程组产生的线程的线程编号 语 ...
- 牛客网PAT练兵场-A除B
题目地址:https://www.nowcoder.com/pat/6/problem/4043 题解:遍历大数,边除边输出,最后得到余数输出即可 /** * *作者:Ycute *时间:2019-1 ...
- 牛客网PAT练兵场-部分A+B
题解:简单循环 题目地址:https://www.nowcoder.com/questionTerminal/fb581ea099a14f5d97c6149cbeee249f /** * *作者:Yc ...
- 使用 K8s 进行作业调度实战分享
最近在公司的数据同步项目(以下简称 ZDTP)中,需要使用到分布式调度数据同步执行单元,目前使用的方案是将数据同步执行单元打包成镜像,使用 K8s 进行调度. 在 ZDTP 中,数据同步的动作可抽象成 ...
- HTTP系列1番外之头部字段大全
原文地址:https://www.jianshu.com/p/6e86903d74f7 常用标准请求头 字段 属性 举例 Accept 设置接受的内容类型 Accept: text/plain Acc ...