【数据库】load data infile上亿条的海量数据导入mysql的那些事
来源:互联网 发布:刘思影被烧后图片知乎 编辑:程序博客网 时间:2024/05/17 09:25
因为做股票金融的,每天产生的数据量是很大的,一个月几十亿的交易记录,也常有出现,特别是今年大跌之前大涨那会。
作为程序员,问题来了,有时需要将一些并不是特别符合规范的csv文件导入数据库中,而且每个文件有十几万行,而这样的文件几万个,于是几十亿的记录如何导入数据库呢?很多想着常用的方法,就是将csv文件读出来,然后一条条插到数据库,或者批量插到数据库,或者开个多线程,然而,花费的时间必须是几十天,而且不好控制,万一中断,那又不知该如何是好了。。。
对于我,我最先想到是开多线程,每次1000条批量插入数据库,然而,由于我犯了一个致命的错误:对于大量数据修改,数据库表先不要建索引,因为每次改动表,索引都会修改,这在数据量大的时候,消耗的时间也是比较大的。所以,我效果并不好,12个小时也才存了4千万数据。看到这个效果,我感觉不对劲,因为我要存的数据,至少是几十亿的,于是我觉得肯定有更效率的方法,直到 load data infile才让我觉得人生处处有惊喜!!
用LOAD DATA INFILE将1.csv导入数据库表d201505的语句如下:LOAD DATA INFILE 'E:/1.csv'INTO TABLE d201505FIELDS TERMINATED BY ','ENCLOSED BY '\"'ESCAPED BY '\\'LINES TERMINATED BY '\n'(stockID,date,price,buysell,volume);就这么一条语句,一个含有十几万数据的导入表中基本是秒级,于是我决定先将我的不规则的csv文件读写成合乎数据表字段的csv,然后LOAD DATA INFILE导入到数据表,并且我开了一百个多线程对文件进行写,开了三个线程对数据导入,效果很乐观,完整一个流程下来,10多亿数据花了八个小时,平均十分钟左右就能导入1500万数据,所以,在此记录下,我的程序如下:
import java.io.File;import java.nio.charset.Charset;import java.sql.Connection;import java.sql.DriverManager;import java.sql.PreparedStatement;import java.sql.SQLException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurrent.TimeUnit;import java.util.regex.Matcher;import java.util.regex.Pattern;//用了javacsv这个插件包import com.csvreader.CsvReader;import com.csvreader.CsvWriter;public class CSVReadAndWrite { // 写cvs文件 public static void writeToCsv(String dirPath, String ym, String d, String[] cvsfile) { ExecutorService pool = Executors.newFixedThreadPool(100); for (int j = 0; j < cvsfile.length; j++) { Thread thread = new MDownThread(dirPath, cvsfile[j], ym, d); pool.execute(thread); } pool.shutdown(); try { pool.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } // 我导入的是201504这一个月的数据,所以是1-30,按天导入 public static void main(String[] args) throws Exception { String ym = "201504"; String d; for (int i = 1; i <= 30; i++) { Date t1 = new Date(); String dirPath = "E:\\" + ym + "/" + ym; d = String.format("%02d", i); dirPath += d + "/"; File file = new File(dirPath); String cvsfile[]; cvsfile = file.list(); if (cvsfile == null || cvsfile.length <= 0) { continue; } System.out.println(dirPath + "开始导入!"); // 写入文件 writeToCsv(dirPath, ym, d, cvsfile); ExecutorService pool2 = Executors.newFixedThreadPool(3); for (int j = 0; j < cvsfile.length; j++) { if (!new File("E:/" + ym + "/" + ym + d + "/" + cvsfile[j]).exists()) { writeToCsv(dirPath, ym, d, cvsfile); } Thread thread2 = new LoadMysqlThread(dirPath, cvsfile[j], ym, d); pool2.execute(thread2); } pool2.shutdown(); try { pool2.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } Date t2 = new Date(); System.out.println(dirPath + "导入成功,用时:" + (t2.getTime() - t1.getTime()) / 1000 + "s"); } }}//线程写csv文件class MDownThread extends Thread { SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); public String dirPath; public String cvsfile; public String ym; public String d; public int dj; public MDownThread(String dirPath, String cvsfile, String ym, String d) { this.dirPath = dirPath; this.cvsfile = cvsfile; this.ym = ym; this.d = d; this.dj = dj; } @Override public void run() { try { // 生成CsvReader对象,以,为分隔符,utf-8编码方式 CsvReader r = new CsvReader(dirPath + cvsfile, ',', Charset.forName("utf-8")); CsvWriter wr = new CsvWriter("E:\\" + ym + "\\" + ym + d + "\\" + cvsfile, ',', Charset.forName("utf-8")); // System.out.println(dirPath+cvsfile[j]); // 逐条读取记录,直至读完 while (r.readRecord()) { String regex = "(\\d+)"; Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(cvsfile); String stockID = ""; while (matcher.find()) { stockID = matcher.group(1); } String date = sdf1.format(sdf.parse(ym + d + r.get(0))); File f = new File("E:\\shamrock\\project\\" + ym + "\\" + ym + d + "\\" + cvsfile); if (!f.getParentFile().exists()) { if (!f.getParentFile().mkdirs()) { return; } } String[] contents = { stockID, date, r.get(1), r.get(2), r.get(3) }; wr.writeRecord(contents); } r.close(); wr.close(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } }}class LoadMysqlThread extends Thread { SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss"); public String dirPath; public String cvsfile; public String ym; public String d; public int dj; public LoadMysqlThread(String dirPath, String cvsfile, String ym, String d) { this.dirPath = dirPath; this.cvsfile = cvsfile; this.ym = ym; this.d = d; this.dj = dj; } //线程导入数据库 @Override public void run() { try { Connection conn = null; String driver = "com.mysql.jdbc.Driver"; String url = "jdbc:mysql://localhost:3306/tickdata"; Class.forName(driver); conn = DriverManager.getConnection(url, "root", "123456"); PreparedStatement pstmt = conn .prepareStatement(" LOAD DATA INFILE 'E:/project/" + ym + "/" + ym + d + "/" + cvsfile + "' INTO TABLE d201505 FIELDS TERMINATED BY ',' ENCLOSED BY '\"' ESCAPED BY '\\\\' LINES TERMINATED BY '\\n' (stockID,date,price,buysell,volume);"); pstmt.execute(); conn.close(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SQLException e) { // TODO Auto-generated catch block e.printStackTrace(); } }}
在此再说一个问题,比如上面的程序在自己电脑,导入本地mysql数据库没问题,但问题来了,因为数据量较大,想让别的电脑也来帮忙,然后存在我的电脑上,换句话说就是电脑A上的数据想导入到电脑B上的mysql中,如果你用上面的命令,肯定会报错找不到文件,因为那语句指定的文件是以mysql的安装路径为相对路径的,所以如果不在B电脑的数据自然会报错,于是此时你要LOCAL来指定是将本地A的数据导入到B mysql中,语法如下:
LOAD DATA LOCAL INFILE 'E:/1.csv' INTO TABLE d201505 FIELDS TERMINATED BY ',' ENCLOSED BY '\"' ESCAPED BY '\\' LINES TERMINATED BY '\n'(stockID,date,price,buysell,volume);
也就是LOAD DATA INFILE中加入LOCAL.....
好了,如果有遇到我这样问题的,希望能帮助到你哦!!!
0 0
- 【数据库】load data infile上亿条的海量数据导入mysql的那些事
- mysql导入数据的方式选择-LOAD DATA INFILE句法
- mysql 导入数据 LOAD DATA LOCAL INFILE
- Mysql导入数据load data infile
- mysql导入数据load data infile用法
- MySQL导入数据load data infile用法
- mysql导入数据load data infile用法
- mysql导入数据load data infile用法
- mysql导入数据load data infile用法
- mysql导入数据load data infile用法
- mysql导入数据load data infile用法
- mysql导入数据load data infile注意事项
- mysql导入数据load data infile用法
- Mysql导入数据load data infile用法
- mysql导入数据load data infile用法
- mysql导入数据load data infile用法
- MySQL 导入数据load data infile用法
- mysql导入数据load data infile用法
- 架构设计模式及框架
- UIButton 不响应或延迟响应 UIControlEventTouchDown 事件的解决办法
- ActiveMQ的安装和配置
- Maven 3 + Hibernate 3.6 + Oracle 11g Example (XML Mapping)
- 迭代器报“vector iterators incompatible”错的几种可能
- 【数据库】load data infile上亿条的海量数据导入mysql的那些事
- ubuntu14.04 + opencv2.4.9配置
- 虚拟网络的管理面临多种挑战
- leetcode 232 Implement Queue using Stacks(难易度:Easy)
- Zoj 3870 Team Formation(异或运算)
- 【CSS】关于CSS样式中的!important、*、_符号
- 设置本地mysql数据库允许远程访问
- 257 Binary Tree Paths
- hadoop2.6.0执行自带wordcount出现异常