优化在大循环中执行“选择”查询的速度

时间:2011-07-05 15:13:05

标签: java oracle jdbc

我正在Java循环中执行一个简单的“select”查询,如下所示。列表的大小可以增长到10000+。如何提高查询速度?任何示例或建议表示赞赏。谢谢。

请注意我需要检索该表的每一列中的所有数据,这就是使用星号(*)的原因。

List<String> valueList = ....
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;

try {
    DriverManager.registerDriver(new oracle.jdbc.OracleDriver());
    conn = DriverManager.getConnection(dbURL, dbUsername, dbPassword);
    for (int m = 0; m < valueList.size() ; m++) {    
         String sql = "SELECT * FROM WORKSHEET WHERE " + sheetId + " = '" +    
                      valueList.get(m) + "'";
         ps = conn.prepareStatement(sql);
         rs = ps.executeQuery();
         // retreive data....           
    }
}

编辑:最后,有几种方法可以加快查询速度。我正在使用第二种方式,因为它将来会阻止ORA-04031错误。

  1. 使用参数化的'SELECT'查询和'IN'子句。
  2. 创建一个嵌套表,并将来自JDBC的项目数组/列表转换为创建的嵌套表。
  3. 创建临时表并插入项目列表。然后对主表执行JOIN(1个查询)并获得结果。

8 个答案:

答案 0 :(得分:6)

尝试提高速度时需要考虑两件事:

  1. 仅针对所有sheetid的
  2. 执行此查询一次
  3. 确保每次执行相同的查询,方法是不对其中的值进行硬编码。 由于这些值可能会更改,因此每个查询将与上一个查询类似,但只有几个不同的值。这将不允许Oracle重用以前的查询,并导致共享池中的不可共享SQL。这将填满共享池。这样做的时间足够长,您将收到ORA-04031错误消息。
  4. 要走的路是使用SQL类型。这是PL / SQL中的一个例子。您可以在Java中使用相同的原则。

    首先创建一个包含一万个sheetId的表:

    SQL> create table worksheet (sheetid)
      2  as
      3   select level
      4     from dual
      5  connect by level <= 10000
      6  /
    
    Table created.
    

    创建SQL类型:

    SQL> create type mynumbers is table of number;
      2  /
    
    Type created.
    

    在您的代码中,使用“valuelist”中的值填充SQL类型的实例,并使用TABLE运算符将类型转换为表值:

    SQL> declare
      2    valuelist mynumbers := mynumbers(23,124,987,6123,8923,1,7139);
      3  begin
      4    for r in
      5    ( select ws.sheetid
      6        from worksheet ws
      7           , table(valuelist) vl
      8       where ws.sheetid = vl.column_value
      9    )
     10    loop
     11      dbms_output.put_line(r.sheetid);
     12    end loop;
     13  end;
     14  /
    1
    23
    124
    987
    6123
    7139
    8923
    
    PL/SQL procedure successfully completed.
    

    现在,共享池中只有一个SQL,只有一个执行此查询,而不是数千个。

答案 1 :(得分:4)

时间主要用于准备和执行查询。

如果您运行一个返回所有结果的查询,那么事情会更快。

即:

String where = "(1=0) "
// first build the where string
for (int m = 0; m < valueList.size() ; m++ ) {
  where = where + " OR (" + sheetId + " = '" + valueList.get(m) + "'";
  }
// then run a single query
sql = "SELECT * FROM WORKSHEET WHERE " + where;
ps = conn.prepareStatement(sql);
rs = ps.executeQuery();
// retrieve and handle data. ....

答案 2 :(得分:3)

您必须使用IN语句准备sql查询,然后只执行一次查询...

答案 3 :(得分:2)

以下是其他一些想法。

  1. 创建临时表并插入(10k)列表项。然后执行到主表的连接(1个查询)并获得结果。

  2. 创建一个存储过程,将项目列表(通过嵌套表格)作为输入,并通过out参数返回结果集。

  3. 我会选择选项1.因为它对我来说更直接,而且可能更快。但是你需要注意并发会话等。不确定你想如何处理多个会话(他们是否会共享这些数据,他们是否会有单独的数据列表?)。

    无论如何要考虑的事情。

答案 4 :(得分:1)

Oracle IN子句中最多可以包含1000个参数。因此,如果您使用预准备语句,您将减少1000倍的迭代次数。只需将列表拆分为1000个元素。

答案 5 :(得分:1)

你可以试试条款:sheetId IN ('1', '2', '3', '4') 请确保列sheetId有一个索引键。

答案 6 :(得分:0)

我不知道这是否会有所改进,但您可以尝试选择所有记录,并在sheetId匹配时检查您的Java代码。这是你应该知道什么是更好的东西。

答案 7 :(得分:0)

这是一个小问题,但如果要动态构造查询(不使用绑定变量),则应使用createStatement,而不是prepareStatement。您不需要使用prepareStatement进行少量开销。