使用SparkSQL实现多线程分页查询并写入文件
一、由于具有多张宽表且字段较多,每个宽表数据大概为4000万条,根据业务逻辑拼接别名,并每张宽表的固定字段进行left join 拼接SQL。这样就能根据每个宽表的主列,根据每个宽表的不同字段关联出一张新的集合。由于下来要进行分页查询,如果要使用SparkSQL进行分页查询,需要增加序号列,那么就在刚才的Sql之前增加一句 create table tableName as SELECT ROW_NUMBER() OVER() as id,* from (拼接的SQL) 就可创建一张带自增序列的,业务需要字段的几张宽表的关联集合,方便下来分页。
for(int i=0;i<ColumnNames.size();i++){
SiCustomerLabelInfoModel Column = ColumnNames.get(i);
List<CiMdaSysTable> ciMdaSysTable = ciCustomerJDao.getMdaSysTableName(Column.getColumnName()); String alias = "t_" + ciMdaSysTable.get(0).getTableId();
String aliasColumn = alias + "." + Column.getColumnName();
String aliasTable = ciMdaSysTable.get(0).getTableName() +" "+ alias; if(mainTable == null){
mainTable = aliasTable;
}
if(ciMdaSysTable.get(0).getUpdateCycle() == 1){
mainTable = aliasTable;
} ColumnNameList.add(aliasColumn);
tableNameList.add(aliasTable);
}
String[] keyAlias = mainTable.split(" ");
String mainKeyColumn = keyAlias[1] + "." + keyColumn;
selectResult.append("select ").append(mainKeyColumn);
if(StringUtil.isNotEmpty(mainTable)){
fromTableName.append(" from ").append(mainTable);
}
Iterator<String> table = tableNameList.iterator();
while(table.hasNext()){
String tableName = table.next();
String[] tableAlias = tableName.split(" ");
String[] mainAlias = mainTable.split(" ");
String alias = tableAlias[1];
String mAlias = mainAlias[1]; if(!mainTable.equals(tableName)){
fromTableName.append(" left join ").append(tableName).append(" on ").append(mAlias).append(".").append(keyColumn)
.append(" = ").append(alias).append(".").append(keyColumn).append(" ");
}
}
fromTableName.append(" ) a");
Iterator<String> column = ColumnNameList.iterator();
while(column.hasNext()){
String columnName = column.next();
selectResult.append(",").append(columnName);
}
selectResult.append(fromTableName);
Createtable.append("create table ").append(cocDwName).append(" as SELECT ROW_NUMBER() OVER() as id,* from").append(" (").append(selectResult);
二、由于业务场景,需要将4000万条数据最终写入10个文件,这里通过声明线程池pool,使用多线程的方法执行,有些人会担心那不会数据错乱吗,不会。因为后面要用分页sql,根据循环传入的 i 的值进行处理。
private ExecutorService pools = Executors.newFixedThreadPool(15);
if(result = true){
String queryCount = "select count(*) from "+cocDwName;
int count = ciCustomerJDao.getDwTotolCount(queryCount);
log.info(""+keyColumn);
try {
for(int i=0;i<10;i++){
CreateDwFileThread jd = new CreateDwFileThread(jndiName,keyColumn,num,cocDwName,count,sysId,i);
Future fu = pools.submit(jd);
fus.add(fu);
}
long start = System.currentTimeMillis();
while (true) {
boolean done = true;
for (Future f : fus) {
if (!f.isDone()) {
done = false;
break;
}
}
if (!done) {
try {
Thread.sleep(1000 * 10);
} catch (InterruptedException e) {
log.error("sleep error", e);
e.printStackTrace();
}
continue;
} else {
break;
}
}
log.debug("wait tasks finish cost:" + (System.currentTimeMillis() - start)); }catch(Exception e){
result = false;
log.error("error", e);
}
}
三、根据第一步创建的表中的自增序列ID进行分页,由于要多线程并发执行,所以不能使用传统分页的begin与end,根据步骤二中传入的 i (这里参数为partNumber)进行处理,根据循环,每条线程执行的开始数据必定以上条数据结束的条数为开始,每次将查询出来的结果集通过list2File写入文件。这里还有个while循环,因为分成10份还是有400万条数据啊,还是觉得大,于是就又分成了10次~就是说每次查询出40万条写入文件,直到新加入400万条flag返回true退出循环。
while(flag == false){
pager.setPageSize(bufferedRowSize);
pager.setPageNum(pageNumber); int begin = (pager.getPageNum() - 1) * pager.getPageSize()+createFileCount*partNumber;
int end = begin + pager.getPageSize();
if(end >= createFileCount*(partNumber+1)){
end = createFileCount*(partNumber+1);
}
StringBuffer sql = new StringBuffer() ;
sql.append(" select ").append(columns).append(" from ").append(cocDwName).append(" where id > ").append(begin).append(" and ").append(" id < ").append(end+1);
JdbcBaseDao jdbcBaseDao = (JdbcBaseDao) SystemServiceLocator.getInstance().getService("jdbcBaseDao");
String BackjndiName = PropertiesUtils.getProperties("JNDI_CI_BACK");
final String file = fileLocalPath + File.separator + dwName+ "_" + String.valueOf(partNumber)+ ".csv";
Log.info("---------sql;:"+ sql + "-------fileName:"+file);
List<Map<String, Object>> dataList = jdbcBaseDao.getBackSimpleJdbcTemplate().queryForList(sql.toString());
if (dataList.size() > 0) {
list2File(dataList, title, columns, file, encode, null, null);
pageNumber++;
}
if(end == createFileCount * partNumber + createFileCount){
flag = true;
}
有人会问你为啥不用ResultSet 直接放入400万条数据 为啥还要分开每40万条数据再分页写~ 我想说 我就是想这么干~ 啊哈哈。。。不过程序中貌似是有问题的 没有考虑到的情景,所以还在推敲。。(Resultset 查出来400万条不还是放在内存中,还是有可能内存溢出的,分页写大不了通过thriftserver多连接几次spark嘛~ 不过代码写的很烂,还在提高哈~)
使用SparkSQL实现多线程分页查询并写入文件的更多相关文章
- mysql查询结果写入文件
注:转自csdn zuyi532 方法1: shell> mysql -uroot -proot -h localhost xxx库 -e " select * from xxx表 l ...
- Linux把查询结果写入到文本
在Linux命令模式下,可以将查询结果写入文件.大概有两种方式,增量写入和覆盖写入. 增量写入: #iostat -m >> /tmp/iostat.txt 覆盖写入: #iostat - ...
- 【CoreData】分页查询和模糊查询
在CoreData实际使用中,分页查询和模糊查询是必不可少的,接下来演示一下: 首先 // 1.创建模型文件 (相当于一个数据库里的表) // New File ———— CoreData ———— ...
- Mybatis包分页查询java公共类
Mybatis包分页查询java公共类 分页----对于数据量非常大的查询中.是不可缺少的. mybatis底层的分页sql语句因为须要我们自己去手动写.而实现分页显示的时候我们须要依据分页查询条 ...
- 【MySQL】分页查询实例讲解
MySQL分页查询实例讲解 1. 前言 本文描述了团队在工作中遇到的一个MySQL分页查询问题,顺带讲解相关知识点,为后来者鉴.本文的重点不是"怎样"优化表结构和SQL语句,而是探 ...
- oracle 12c 新特性之(相同字段上的多重索引、ddl 日志、限制PGA的大小、分页查询)
1. 相同字段上的多重索引 在Oracle 12c R1之前,一个字段是无法以任何形式拥有多个索引的.或许有人会想知道为什么通常一个字段需要有多重索引,事实上需要多重索引的字段或字段集合是很多的. ...
- JAVAEE——BOS物流项目04:学习计划、datagrid、分页查询、批量删除、修改功能
1 学习计划 1.datagrid使用方法(重要) n 将静态HTML渲染为datagrid样式 n 发送ajax请求获取json数据创建datagrid n 使用easyUI提供的API创建data ...
- 【1】MySQL大数据量分页查询方法及其优化
---方法1: 直接使用数据库提供的SQL语句---语句样式: MySQL中,可用如下方法: SELECT * FROM 表名称 LIMIT M,N---适应场景: 适用于数据量较少的情况(元组百/千 ...
- mysql分库 分页查询
Mysql海量数据分表分库如何列表分页? 1.现在使用ElasticSearch了.基于Lucene的解决方案 2.必须将mysql里的数据写入到类似hbase这样的分布式数据库,查询快.但分页.查询 ...
随机推荐
- C#部分---"++"在前在后的区别。
int a=5; int b=a++;//int b=a;a=a+1 int c=++a;//a=a+1;int c=a
- js调用百度地图API创建地图
技术交流群:233513714 <html xmlns="http://www.w3.org/1999/xhtml"><head runat="serv ...
- Android平台下的JNI开发
JNI是Java Native Interface的缩写,通过JNI可以方便我们在Android平台上进行C/C++编程.要用JNI首先必须安装Android的NDK,配置好NDK环境之后就可以在Ec ...
- socket、webService、RMI ?
网络七层协议为:物理层.数据链路层.网络层.传输层.会话层.表示层.应用层 webService > RMI > socket RMI比socket更高一点 socket 只是 java在 ...
- vb6 判断64位操作系统
Option Explicit Private Declare Function GetCurrentProcess Lib "kernel32" () As Long Priva ...
- 怎么用EDIUS实现跟踪马赛克效果
我们经常会在一些新闻的视频中看到一些马赛克,这些马赛克一般都是保护人物的隐私权,肖像权什么的.我们时常也会看到即使人物位置发生了变化,被遮挡的地方依旧还是被遮挡住,一点也不用担心因为人物运动而使马赛克 ...
- Python 统计IIS日志行数
__author__ = 'Administrator' import codecs def blocks(file, size=65536): while True: b = file.read(s ...
- Q7: Unique Binary Search Trees
问题描述: Given n, how many structurally unique BST's (binary search trees) that store values 1...n? For ...
- 什么是JDK
Java Development Kit (JDK) 是太阳微系统针对Java开发人员发布的免费软件开发工具包(SDK,Software development kit).JDK 是整个Java的核心 ...
- vs2010 release 模式加了断点,跑代码无法跟踪,解决方法
纯跑代码,不是附加进程调试. 打开不能调试的类库项目属性页面→切换到生成选项卡→点击高级按钮→将调试信息一项设置 将“调试信息”设置为“pdb-only”. 我是按图上的设置就正常了. -- 201 ...