提高查询处理速度

时间:2010-08-23 22:57:28

标签: java mysql jdbc

我的查询处理时间存在重大问题:( 我认为这是因为查询正在重新编译evrytime。但我没有看到任何解决方法。 以下是代码的查询/片段:

private void readPerformance(String startTime, String endTime,
        String performanceTable, String interfaceInput) throws SQLException, IOException {
    String interfaceId, iDescp, iStatus = null;
    String dtime, ingress, egress, newLine, append, routerId= null;
    StringTokenizer st = null;
    stmtD = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,  
            java.sql.ResultSet.CONCUR_READ_ONLY);
    stmtD.setFetchSize(Integer.MIN_VALUE); 
    BufferedReader interfaceRead = new BufferedReader(new FileReader(interfaceInput));
    BufferedWriter pWrite = new BufferedWriter(new FileWriter("performanceInput.txt"));

    while((newLine = interfaceRead.readLine())!= null){
        st = new StringTokenizer(newLine,",");
        while(st.hasMoreTokens()){
            append = st.nextToken()+CSV+st.nextToken()+st.nextToken()+CSV+st.nextToken();
            System.out.println(append +" ");
            iStatus = st.nextToken().trim();
            interfaceId = st.nextToken().trim();
            append = append + CSV+iStatus+CSV+interfaceId;
            System.out.println(append +" ");
            pquery = " Select d.dtime,d.ifInOctets, d.ifOutOctets from "+performanceTable+"_1_60" +" AS d Where d.id = " +interfaceId 
            + " AND dtime BETWEEN " +startTime+ " AND "+ endTime;
            rsD = stmtD.executeQuery(pquery); 
            /* interface query*/
            while(rsD.next()){
                            dtime = rsD.getString(1);
                    ingress= rsD.getString(2);
                    egress = rsD.getString(3);
                    pWrite.write(append + CSV + dtime+CSV+ingress+CSV+egress+NL);

            }//end while
        }//end while
    }// end while

    pWrite.close();
    interfaceRead.close();
    rsD.close() ;   
    stmtD.close();

}

我的interfaceId值不断变化。所以我把查询放在循环中导致多次重新编译查询。

有任何betetr方式吗?我可以在java中起诉存储过程吗?如果是这样的话?对它没有多少了解。

当前处理时间差不多是60分钟(:(()!!!生成的文本文件超过300 MB 请帮忙!!!

谢谢。

3 个答案:

答案 0 :(得分:1)

您可以使用PreparedStatement和参数,这可能会避免重新编译查询。由于performanceTable是常量,因此可以将其放入准备好的查询中。在WHERE条件中使用的其余变量被设置为参数。

在循环外部,创建一个预准备语句,而不是常规语句:

   PreparedStatement stmtD = conn.prepareStatement(
         "Select d.dtime,d.ifInOctets, d.ifOutOctets from "+performanceTable+"_1_60 AS d"+ 
         " Where d.id = ? AND dtime BETWEEN ? AND ?");

然后,在循环中,设置参数:

   stmtD.setInteger(1, interfaceID);
   stmtD.setInteger(2, startTime);
   stmtD.setInteger(3, endTime);
   ResultSet rsD = stmtD.executeQuery();  // note no SQL passed in here

最好还是使用EXPLAIN检查来自MySQL的查询计划,看看它是否也是瓶颈的一部分。此外,函数中还有相当多的诊断字符串连接。一旦查询正常,删除它也可以提高性能。

最后,请注意,即使查询速度很快,网络延迟也可能会降低速度。 JDBC提供多个查询的批量执行,以帮助减少每个语句的总体延迟。请参阅Connection上的addBatch / executeBatch。

答案 1 :(得分:1)

需要更多信息,但我可以提供一些一般性问题/建议。它可能与编译查询计划无关(这是不寻常的)

  • id和dtime列是否已编入索引?
  • 在60分钟内执行查询的次数是多少次?
  • 每个查询需要多长时间?

如果每个查询的时间很长,则问题是查询执行本身,而不是编译。如上所述检查索引。

如果有许多查询,则可能是造成问题的大量查询。使用PreparedStatement(请参阅mdma的答案)可能有所帮助。或者,您可以尝试使用“in”语句批量处理所需的interfaceID,并为每100个interfaceID运行一个查询,而不是每个都有一个。

编辑:作为一个好的做法,您应该始终使用PreparedStatement,因为它将正确处理日期等数据类型,因此您不必担心将它们格式化为正确的SQL语法。还可以防止SQL注入。

答案 2 :(得分:0)

从你看起来很多选择的问题开始(根据你的文件大小,甚至是100) 而不是这样做,而是从输入文件创建所有interfaceId值的逗号分隔列表,然后使用“IN”关键字进行1次SQL调用。你知道performanceTable,startTime和endTime没有改变,所以查询看起来像这样

SELECT d.dtime,d.ifInOctets, d.ifOutOctets 
FROM MyTable_1_60 as d 
WHERE dtime BETWEEN '08/14/2010' AND '08/15/2010'
AND d.id IN ( 10, 18, 25, 13, 75 ) 

然后您可以自由打开文件,一次性转储结果集。