精华帖 (8) :: 良好帖 (2) :: 新手帖 (0) :: 隐藏帖 (8)
|
|
---|---|
作者 | 正文 |
发表时间:2008-09-14
我觉得这样的数据导入处理问题,没有必要自己写程序还要控制异常的;
最好用ETL,画好流程图,然后直接调用bat或者sh脚本,啥事都不用管,而且还能记录Log; 我用的是Kettle,最后的一步不是insert也不是update,而是insert/update; 我没搞过楼主说的那么大的数据量,我的就是几千条,但每条涉及16个表的插入和更新,速度还满意。 看了这么多回复,我比较看好 抛出异常的爱 和 wolfbrood提到的做法: 1) insert into temp table 2) 在temp table增加一个flag,并设置初始值: isRepeated=0 3) 然后select并把已经存在的标记改为isRepeated=1 4) 把isRepeated=0的记录insert正式表 5) 删除temp table中的isRepeated=1的记录 当然 也可以像tommy402 说的,可以借助于内存表或者缓存 1)insert之前,把已经存在的记录的关键字都提取到内存表中 2) insert into a select * from b where b.id not exists (select 'x' from b where a.id = b.id) |
|
返回顶楼 | |
发表时间:2008-09-14
cuiyi.crazy 写道 我觉得这样的数据导入处理问题,没有必要自己写程序还要控制异常的;
最好用ETL,画好流程图,然后直接调用bat或者sh脚本,啥事都不用管,而且还能记录Log; 我用的是Kettle,最后的一步不是insert也不是update,而是insert/update; 我没搞过楼主说的那么大的数据量,我的就是几千条,但每条涉及16个表的插入和更新,速度还满意。 看了这么多回复,我比较看好 抛出异常的爱 和 wolfbrood提到的做法: 1) insert into temp table 2) 在temp table增加一个flag,并设置初始值: isRepeated=0 3) 然后select并把已经存在的标记改为isRepeated=1 4) 把isRepeated=0的记录insert正式表 5) 删除temp table中的isRepeated=1的记录 当然 也可以像tommy402 说的,可以借助于内存表或者缓存 1)insert之前,把已经存在的记录的关键字都提取到内存表中 2) insert into a select * from b where b.id not exists (select 'x' from b where a.id = b.id) 目前我是采用了捕获异常,唯一索引的方案。 但好久都觉得ETl才更快,我知道ETL可以做很多事情,以前面试一家搞BI的,所以对ETL也了解过, 我用过微软的SSIS,指数初级阶段,对于更复杂的数据转换及其他控制我还不会。可目前恰恰正是我需要的。 我不是拿方案的人,只是建议性的私下摸索,最后还得上头说了算。不过还是学到了很多 |
|
返回顶楼 | |
发表时间:2008-09-14
先说明我不是DBA,所以给的方案可能不一定符合数据库设计的美观。
我觉得如果有重复,那么重复的字段应该与业务有关 完全可以根据业务字段分区,如AB开头的数据放在Test_AB中,或者是用类HashCode的算法进行分类,然后估算规模,完全可以将一张表的数据控制在一个理想的范围。 如果数据增长超出预期,那么可以考虑迁移,重做数据库。(细节不讨论) 如果是我做的话,加个Lucene分段索引(只对指定字段索引),多了不好说,做个亿级的,速度应该没有大的问题。(如果再多,加几台机器分区处理了。) 其实最根本的东西,还是你的规模估算。 |
|
返回顶楼 | |
发表时间:2008-09-16
/** * 分解采集的数据集,到两个参数组中去 这里要根据主表的ORGIN_ID去进行分析判断 * * @throws TaskAppConfigException */ private void partitionInsertAndUpdateList(Mapping mapping, List<FieldMapping> fieldMappings, List<Map> insertDatas, List<Map> updateDatas, List<Map> datas) throws TaskAppConfigException { LOG.info(new StringBuffer("★ 开始分析采集到的原始数据. . .")); long startTimes = System.currentTimeMillis(); insertDatas.clear(); updateDatas.clear(); // TODO 这里fieldMappings.get(0)是个很大的bad smell String aliasA = mapping.getFieldMappingFieldAAlias(); Table tableA = mapping.getTableByAlias(aliasA); String aliasB = fieldMappings.get(0).getAlias( FieldMapping.ATTR_KEY_FIELD_B); Table tableB = mapping.getTableByAlias(aliasB); int batchNum = 50; int startIndex = 1; DataPage batchPage = new DataPage(startIndex, datas.size(), batchNum); StringBuffer checkUniqueSqlA = new StringBuffer(); checkUniqueSqlA.append("select nvl2(b.").append( tableB.getExtSysIdField().getName()).append( ",'1','0') as IS$EXIST from table(str2varlist_order('"); StringBuffer checkUniqueSqlB = new StringBuffer(); Object extSysIdFieldValue = null; String extSysIdFieldName = aliasA + "$" + tableA.getPrimaryKeyField().getName(); Field extSysIdField = tableB.getExtSysIdField(); Map dataRow = null; for (; batchPage.getPageIndex() <= batchPage.getTotalPages(); batchPage .setPageIndex(batchPage.getPageIndex() + 1)) { checkUniqueSqlB = new StringBuffer(); for (int i = (int) batchPage.getStart(); i <= batchPage.getEnd(); i++) { dataRow = datas.get(i - 1); // 这里要做数据转换 extSysIdFieldValue = dataRow.get(extSysIdFieldName); if (Field.FIELD_TYPE_NAME_STRING .equals(extSysIdField.getType())) { String tempString = null; if (extSysIdFieldValue instanceof Number) { tempString = ((Number) extSysIdFieldValue).toString(); extSysIdFieldValue = tempString; } } else if (Field.FIELD_TYPE_NAME_NUMERIC.equals(extSysIdField .getType())) { if (extSysIdFieldValue instanceof String) { extSysIdFieldValue = Long .parseLong((String) extSysIdFieldValue); } } checkUniqueSqlB.append(extSysIdFieldValue).append(","); } checkUniqueSqlB.deleteCharAt(checkUniqueSqlB.length() - 1); checkUniqueSqlB.append("')) a, ").append(tableB.getName()).append( " b "); checkUniqueSqlB.append(" where a.var = b.").append( tableB.getExtSysIdField().getName()).append("(+)"); if (tableB.getExtSysTypeField() != null) { checkUniqueSqlB.append(" and b.").append( tableB.getExtSysTypeField().getName()).append("(+)=") .append(tableA.getExtSysTypeValue()); } String sql = checkUniqueSqlA.toString() + checkUniqueSqlB.toString(); List<Map> results = this.queryForList(sql); int i = (int) batchPage.getStart(); for (Map aData : results) { String isExist = (String) aData.get("IS$EXIST"); if (isExist.equals("0")) { insertDatas.add(datas.get(i - 1)); } else if (isExist.equals("1")) { updateDatas.add(datas.get(i - 1)); } i++; } } // mannul -DtaskID=ftrade$boss$task -DtaskType=DATE_RANGE LOG.info("★ 已经采集的原始数据分析完毕.【待UPDATE记录共: " + updateDatas.size() + " 条】" + "【待INSERT记录共: " + insertDatas.size() + " 条】 【用时" + (System.currentTimeMillis() - startTimes) + "毫秒】"); }
|
|
返回顶楼 | |
发表时间:2008-09-16
wl95421 写道 先说明我不是DBA,所以给的方案可能不一定符合数据库设计的美观。
我觉得如果有重复,那么重复的字段应该与业务有关 完全可以根据业务字段分区,如AB开头的数据放在Test_AB中,或者是用类HashCode的算法进行分类,然后估算规模,完全可以将一张表的数据控制在一个理想的范围。 如果数据增长超出预期,那么可以考虑迁移,重做数据库。(细节不讨论) 如果是我做的话,加个Lucene分段索引(只对指定字段索引),多了不好说,做个亿级的,速度应该没有大的问题。(如果再多,加几台机器分区处理了。) 其实最根本的东西,还是你的规模估算。 有这么复杂吗?这是一个简单的数学问题而不是一个复杂的工程问题 |
|
返回顶楼 | |
发表时间:2008-09-16
楼上这么多讨论有些已经很接近正确的解决方案了:
1。首先导入数据需要经过过滤处理(数据少就DB外处理,数据多就临时表,这点异常的经验是对的) 2。唯一键是必要的,异常处理也是要的 |
|
返回顶楼 | |
发表时间:2008-09-16
cuiyi.crazy 写道 我觉得这样的数据导入处理问题,没有必要自己写程序还要控制异常的;
最好用ETL,画好流程图,然后直接调用bat或者sh脚本,啥事都不用管,而且还能记录Log; 我用的是Kettle,最后的一步不是insert也不是update,而是insert/update; 我没搞过楼主说的那么大的数据量,我的就是几千条,但每条涉及16个表的插入和更新,速度还满意。 看了这么多回复,我比较看好 抛出异常的爱 和 wolfbrood提到的做法: 1) insert into temp table 2) 在temp table增加一个flag,并设置初始值: isRepeated=0 3) 然后select并把已经存在的标记改为isRepeated=1 4) 把isRepeated=0的记录insert正式表 5) 删除temp table中的isRepeated=1的记录 当然 也可以像tommy402 说的,可以借助于内存表或者缓存 1)insert之前,把已经存在的记录的关键字都提取到内存表中 2) insert into a select * from b where b.id not exists (select 'x' from b where a.id = b.id) 如果是实时的这样还不如直接select count(*) 然后 insert 快 如果不实时怎么保证数据的一实时性,用户insert 以后,马上可以看到 |
|
返回顶楼 | |
发表时间:2008-09-16
方法2:写trigger,在插入之前做一个查询,如果有就抛弃,没有就插入数据
这个方法比较好,很实用 |
|
返回顶楼 | |
发表时间:2008-09-16
几十万的记录不是很大啊,你可以在你的客户端实现比较啊!
|
|
返回顶楼 | |
发表时间:2008-09-16
tou3921 写道 cuiyi.crazy 写道 我觉得这样的数据导入处理问题,没有必要自己写程序还要控制异常的;
最好用ETL,画好流程图,然后直接调用bat或者sh脚本,啥事都不用管,而且还能记录Log; 我用的是Kettle,最后的一步不是insert也不是update,而是insert/update; 我没搞过楼主说的那么大的数据量,我的就是几千条,但每条涉及16个表的插入和更新,速度还满意。 看了这么多回复,我比较看好 抛出异常的爱 和 wolfbrood提到的做法: 1) insert into temp table 2) 在temp table增加一个flag,并设置初始值: isRepeated=0 3) 然后select并把已经存在的标记改为isRepeated=1 4) 把isRepeated=0的记录insert正式表 5) 删除temp table中的isRepeated=1的记录 当然 也可以像tommy402 说的,可以借助于内存表或者缓存 1)insert之前,把已经存在的记录的关键字都提取到内存表中 2) insert into a select * from b where b.id not exists (select 'x' from b where a.id = b.id) 目前我是采用了捕获异常,唯一索引的方案。 但好久都觉得ETl才更快,我知道ETL可以做很多事情,以前面试一家搞BI的,所以对ETL也了解过, 我用过微软的SSIS,指数初级阶段,对于更复杂的数据转换及其他控制我还不会。可目前恰恰正是我需要的。 我不是拿方案的人,只是建议性的私下摸索,最后还得上头说了算。不过还是学到了很多 删除temp表的记录是否有隐患,删除的记录是否被真正删除掉,是否还要占空间,是否要定期做优化。 |
|
返回顶楼 | |