我需要在Oracle中快速插入许多小行。 (5个领域)。
使用MySQL,我将插入分成100个组,然后对每组100个插入使用一个插入语句。
但是对于Oracle,用户反馈是质量插入(从1000到30000之间)太慢了。
我是否可以使用类似的技巧来加速从Java到Oracle的程序化插入?
答案 0 :(得分:10)
您可以使用Spring的DAO模块批量插入多行。
在一次更新中将Order对象集合插入数据库的示例:
public class OrderRepositoryImpl extends SimpleJdbcDaoSupport implements
OrderRepository {
private final String saveSql = "INSERT INTO orders(userid, username, coffee, coffeename, amount) "
+ "VALUES(?, ?, ?, ?, ?)";
public void saveOrders(final Collection<Order> orders) {
List<Object[]> ordersArgumentList = new ArrayList<Object[]>(orders
.size());
Object[] orderArguments;
for (Order order : orders) {
orderArguments = new Object[] { order.getUserId(),
order.getUserName(), order.getCoffe(),
order.getCoffeeName(), order.getAmount() };
ordersArgumentList.add(orderArguments);
}
getSimpleJdbcTemplate().batchUpdate(saveSql, ordersArgumentList);
}
}
答案 1 :(得分:2)
您不会保留将这些记录传递到数据库的方式。最好的方法是使用数组,因为这允许使用Oracle的大量漂亮的FORALL批量操作。
此示例包有两个过程。一个填充T23记录集合(一个包含五个数字列的表)和一个使用数组批量插入记录到该表中的记录。
SQL> create or replace package p23 as
2 type t23_nt is table of t23%rowtype;
3 function pop_array ( p_no in number )
4 return t23_nt;
5 procedure ins_table ( p_array in t23_nt );
6 end p23;
7 /
Package created.
SQL> create or replace package body p23 as
2
3 function pop_array ( p_no in number )
4 return t23_nt
5 is
6 return_value t23_nt;
7 begin
8 select level,level,level,level,level
9 bulk collect into return_value
10 from dual
11 connect by level <= p_no;
12 return return_value;
13 end pop_array;
14
15 procedure ins_table
16 ( p_array in t23_nt )
17 is
18 s_time pls_integer;
19 begin
20
21 s_time := dbms_utility.get_time;
22
23 forall r in p_array.first()..p_array.last()
24 insert into t23
25 values p_array(r);
26
27 dbms_output.put_line('loaded '
28 ||to_char(p_array.count())||' recs in '
29 ||to_char(dbms_utility.get_time - s_time)
30 ||' csecs');
31 end ins_table;
32 end p23;
33 /
Package body created.
SQL>
以下是一些示例运行的输出:
SQL> declare
2 l_array p23.t23_nt;
3 begin
4 l_array := p23.pop_array(500);
5 p23.ins_table(l_array);
6 l_array := p23.pop_array(1000);
7 p23.ins_table(l_array);
8 l_array := p23.pop_array(2500);
9 p23.ins_table(l_array);
10 l_array := p23.pop_array(5000);
11 p23.ins_table(l_array);
12 l_array := p23.pop_array(10000);
13 p23.ins_table(l_array);
14 l_array := p23.pop_array(100000);
15 p23.ins_table(l_array);
16 end;
17 /
loaded 500 recs in 0 csecs
loaded 1000 recs in 0 csecs
loaded 2500 recs in 0 csecs
loaded 5000 recs in 1 csecs
loaded 10000 recs in 1 csecs
loaded 100000 recs in 15 csecs
PL/SQL procedure successfully completed.
SQL>
SQL> select count(*) from t23
2 /
COUNT(*)
----------
119000
SQL>
我认为在0.15秒内插入100,000条记录应该让所有用户满意。那么,问题是,你如何处理插入?
答案 2 :(得分:0)
现在MySQL是Oracle,所以也许一个更简单的解决方案就是留在MySQL上......
如果没有,那么您应确保在启动插入组之前启动事务,一旦组完成,然后提交事务并为下一组插入启动新事务。
还要检查可能会减慢插入时间的不必要的索引定义。
...更新
批量插入是指ETL(提取转换加载)的最后一步,因此您是否考虑使用基于Java的ETL工具,例如pentaho kettle或talend-studio。
Pentaho描述了他们的Oracle批量加载设施here。
快速谷歌还展示了一些初步证据,表明Talend也对Oracle批量加载有一些支持。
答案 3 :(得分:0)
尝试
public Boolean inserTable(String fileName) {
logger.info("Begin - " + this.getClass().getSimpleName() + "." + "inserTable");
logger.info("File : " + fileName);
try (Connection conn1 = jdbcTemplate.getDataSource().getConnection();) {
OracleConnection conn = ( OracleConnection ) conn1.getMetaData().getConnection();
ScriptRunner sr = new ScriptRunner(conn);
StringBuilder sBuffer = new StringBuilder();
StringBuffer sb=new StringBuffer();
String query = "Insert into TABLE_DATA (ID, DATA1, DATECREATED, CREATEDBY) Values ";
String line = "";
//Creating a reader object
BufferedReader br = new BufferedReader(new FileReader(fileName),1024 * 1024 );
while ((line = br.readLine()) != null) {
//logger.info("Leyo linea : " + line);
sb.append(query.concat("(").concat("TABLE_DATA_SQ.NEXTVAL,").concat(line.substring(0,6)).concat(",").concat("sysdate,").concat("'BDVENLINEA'").concat(");"));
sb.append("\n");
}
sb.append("commit;");
Reader reader = new StringReader(sb.toString());
//Running the script
sr.runScript(reader);
reader.close();
br.close();
return true;
} catch (FileNotFoundException e) {
logger.error(e.getMessage(), e);
throw new TechnicalException(e, e.getMessage());
} catch (SQLException e) {
e.printStackTrace();
throw new TechnicalException(e, e.getMessage());
} catch (IOException e) {
e.printStackTrace();
throw new TechnicalException(e, e.getMessage());
} finally {
logger.info("End - " + this.getClass().getSimpleName() + "." + "inserTable");
}
}