news 2026/4/24 20:13:39

mysql数据快速导入doris

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
mysql数据快速导入doris

mysql数据快速导入doris

  • 背景
  • 问题
  • 解决
  • 最后

背景

前段时间业务需要将mysql数据导入到doris ,以便大数据平台使用

问题

本来想法很简单,doris 语法兼容mysql,将数据导出为insert 语句,直接插入就行。
想法不错,但是奈何数据量大(200多w),插入几个钟头还没完事。后来想想,试试批量insert语句。也挺慢。听说csv导入doris挺快的,奈何又遇到分隔符问题,简单说就是没有转义,导致列数不对。难道没有完美方法

解决

办法还是有的,可以将插入sql转换为csv,并转义(分界符),代码如下:

importjava.io.BufferedReader;importjava.io.FileReader;importjava.io.FileWriter;importjava.io.IOException;importjava.util.ArrayList;importjava.util.List;/***简化但可靠的SQL转CSV工具*/publicclassInsertSqlToCSV{publicstaticvoidmain(String[]args)throwsIOException{if(args.length<2){System.out.println("使用方法: java InsertSqlToCSV <输入SQL文件> <输出CSV文件>");return;}convertSqlToCsv(args[0],args[1]);}publicstaticvoidconvertSqlToCsv(StringsqlFile,StringcsvFile)throwsIOException{List<String[]>allData=newArrayList<>();List<String>headers=null;inttotalRows=0;intsuccessRows=0;interrorRows=0;System.out.println("开始处理: "+sqlFile);try(BufferedReaderbr=newBufferedReader(newFileReader(sqlFile));FileWriterfw=newFileWriter(csvFile)){Stringline;intlineNum=0;while((line=br.readLine())!=null){lineNum++;line=line.trim();if(line.toUpperCase().startsWith("INSERT INTO")){totalRows++;try{//提取字段名(只从第一行提取)if(headers==null){headers=extractHeaders(line);System.out.println("提取到 "+headers.size()+" 个字段");}//提取VALUES部分StringvaluesPart=extractValuesPart(line);//解析VALUESList<String>values=parseSimple(valuesPart);//验证列数if(values.size()!=headers.size()){System.out.println("第 "+lineNum+" 行: 期望 "+headers.size()+" 列,实际 "+values.size()+" 列");errorRows++;continue;}allData.add(values.toArray(newString[0]));successRows++;}catch(Exceptione){System.out.println("第 "+lineNum+" 行解析失败: "+e.getMessage());errorRows++;}}}System.out.println("\n处理完成:");System.out.println("总INSERT语句: "+totalRows);System.out.println("成功: "+successRows);System.out.println("失败: "+errorRows);if(successRows==0){System.out.println("没有成功解析的数据!");return;}//写入CSVwriteCsv(fw,headers,allData);System.out.println("CSV文件已生成: "+csvFile);}catch(Exceptione){System.err.println("处理失败: "+e.getMessage());e.printStackTrace();}}/***提取字段名*/privatestaticList<String>extractHeaders(Stringsql){List<String>headers=newArrayList<>();//找到字段列表的开始intstart=sql.indexOf('(');if(start==-1)returnheaders;//找到字段列表的结束intend=sql.indexOf(')',start);if(end==-1)returnheaders;StringheaderPart=sql.substring(start+1,end).trim();//简单分割字段名String[]parts=headerPart.split(",");for(Stringpart:parts){Stringheader=part.trim();//移除引号if(header.startsWith("`")&&header.endsWith("`")){header=header.substring(1,header.length()-1);}elseif(header.startsWith("\"")&&header.endsWith("\"")){header=header.substring(1,header.length()-1);}elseif(header.startsWith("'")&&header.endsWith("'")){header=header.substring(1,header.length()-1);}elseif(header.startsWith("[")&&header.endsWith("]")){header=header.substring(1,header.length()-1);}headers.add(header);}returnheaders;}/***提取VALUES部分*/privatestaticStringextractValuesPart(Stringsql){//找到VALUES关键字intvaluesIndex=sql.toUpperCase().indexOf("VALUES");if(valuesIndex==-1){thrownewIllegalArgumentException("未找到VALUES关键字");}StringafterValues=sql.substring(valuesIndex+"VALUES".length()).trim();//移除末尾分号if(afterValues.endsWith(";")){afterValues=afterValues.substring(0,afterValues.length()-1);}//找到括号内容intopenParen=afterValues.indexOf('(');intcloseParen=afterValues.lastIndexOf(')');if(openParen==-1||closeParen==-1||closeParen<=openParen){thrownewIllegalArgumentException("未找到有效的VALUES括号");}returnafterValues.substring(openParen+1,closeParen).trim();}/***简单但可靠的解析器*/privatestaticList<String>parseSimple(StringvaluesStr){List<String>values=newArrayList<>();StringBuildercurrent=newStringBuilder();booleaninQuotes=false;charquoteChar='\0';for(inti=0;i<valuesStr.length();i++){charc=valuesStr.charAt(i);if(!inQuotes){//不在引号内if(c=='\''||c=='"'){inQuotes=true;quoteChar=c;current.append(c);}elseif(c==','){//字段分隔符Stringvalue=cleanValue(current.toString().trim());values.add(value);current.setLength(0);}else{current.append(c);}}else{//在引号内current.append(c);if(c==quoteChar){//检查是否是转义引号if(i+1<valuesStr.length()&&valuesStr.charAt(i+1)==quoteChar){//是转义引号,跳过下一个current.append(quoteChar);i++;}else{//是结束引号inQuotes=false;}}}}//最后一个值if(current.length()>0){Stringvalue=cleanValue(current.toString().trim());values.add(value);}returnvalues;}/***清理值*/privatestaticStringcleanValue(Stringvalue){value=value.trim();if(value.equalsIgnoreCase("NULL")){return"";}//移除外层引号if((value.startsWith("'")&&value.endsWith("'"))||(value.startsWith("\"")&&value.endsWith("\""))){value=value.substring(1,value.length()-1);//处理转义引号value=value.replace("''","'").replace("\"\"","\"");}returnvalue;}/***写入CSV*/privatestaticvoidwriteCsv(FileWriterwriter,List<String>headers,List<String[]>data)throwsIOException{//写入表头List<String>escapedHeaders=newArrayList<>();for(Stringheader:headers){escapedHeaders.add(escapeCsv(header));}writer.write(String.join(",",escapedHeaders));writer.write("\n");//写入数据for(String[]row:data){List<String>escapedRow=newArrayList<>();for(Stringcell:row){escapedRow.add(escapeCsv(cell));}writer.write(String.join(",",escapedRow));writer.write("\n");}}/***CSV转义*/privatestaticStringescapeCsv(Stringvalue){if(value==null)return"";//if(value.contains(",")||value.contains("\"")||//value.contains("\n")||value.contains("\r")){//value=value.replace("\"","\"\"");//return"\""+value+"\"";//}//移除可能已经存在的外层单引号Stringprocessed=value.trim();booleanhadQuotes=false;if(processed.startsWith("'")&&processed.endsWith("'")&&processed.length()>1){processed=processed.substring(1,processed.length()-1);hadQuotes=true;}//转义处理StringBuilderresult=newStringBuilder();for(inti=0;i<processed.length();i++){charc=processed.charAt(i);if(c=='\\'){//反斜杠转义result.append("\\\\");}elseif(c=='\''){//单引号转义result.append("\\'");}else{result.append(c);}}//如果原始值有引号或者我们需要加引号,就加上if(hadQuotes||!processed.isEmpty()){return"'"+result.toString()+"'";}else{returnresult.toString();}}}

这样处理后,250万行的sql转csv,大概10分钟左右,然后csv导入doris ,几秒就行

最后

如果那位有更好办法,可以联系我:lita2lz

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 10:35:24

ant-design-vue组件设置中文

//app.vue<script setup lang"ts"> import {inject} from vue //添加1 import BasicLayout from /layouts/BasicLayout.vue import {LoginUserStore} from /stores/LoginUserStore.tsconst locale inject(locale)//添加2const loginUserStore LoginUserStore…

作者头像 李华
网站建设 2026/4/23 12:58:17

Multisim示波器使用:提升教学直观性的实践方法

让“看不见的电信号”跃然屏上&#xff1a;用Multisim示波器重构电子电路教学你有没有遇到过这样的课堂场景&#xff1f;讲台上老师认真推导着RC滤波器的频率响应公式&#xff0c;台下学生却一脸茫然&#xff1a;“这个‘衰减’到底长什么样&#xff1f;”又或者&#xff0c;在…

作者头像 李华
网站建设 2026/4/24 5:32:58

被生活投喂的小确幸,藏不住啦~​

捕捉日常中的小确幸留意身边细微的美好瞬间&#xff0c;比如清晨的阳光、一杯热茶、陌生人的微笑。这些看似平凡的细节往往能带来意想不到的温暖和快乐。养成记录的习惯&#xff0c;用手机拍照或写日记的方式将这些小确幸保存下来。回顾时会发现生活其实充满闪光点。培养感恩的…

作者头像 李华
网站建设 2026/4/18 3:43:51

useState是同步的还是异步的?

useState 在 React 的合成事件处理函数和生命周期函数中表现为异步&#xff0c;但在 某些特定情况下会表现出同步行为。这是一个常见的 React 面试题&#xff0c;需要分情况讨论&#xff1a;1. 异步场景&#xff08;最常见&#xff09;在 React 的事件处理函数和生命周期中&…

作者头像 李华
网站建设 2026/4/18 20:29:24

【2025最新】基于SpringBoot+Vue的智能物流管理系统管理系统源码+MyBatis+MySQL

摘要 随着电子商务和全球贸易的快速发展&#xff0c;物流行业在国民经济中的地位日益凸显。传统物流管理方式依赖人工操作&#xff0c;效率低下且容易出错&#xff0c;难以满足现代企业对高效、精准物流服务的需求。智能物流管理系统通过整合信息技术与物流管理&#xff0c;能够…

作者头像 李华
网站建设 2026/4/17 14:14:11

【前端开发】Nuxt.js 国际化插件 i18n 使用指南

nuxtjs/i18n 官方文档&#xff1a;Nuxt I18nnuxtjs/i18n 是 Nuxt 官方基于 vue-i18n &#xff08;Vue.js 的通用国际化插件&#xff09;封装的国际化&#xff08;i18n&#xff09;模块&#xff0c;用于为 Nuxt 应用提供多语言支持。它简化了多语言路由、语言切换、翻译管理等功…

作者头像 李华