Java:如何有效地从数据库中读取?

use*_*490 4 java sql performance

我试图从java中的sql数据库读出一列,我希望结果在数组中返回.这是功能:

public static double[] open(Connection conn,String symbol,int startdate,int enddate)                 throws SQLException {
    int id = database.get_stockid(conn, symbol);
    Statement stat = conn.createStatement();
    ResultSet rs = stat.executeQuery("select price_open from stock_data where stock_id="+id+" and date>="+startdate+" and date<="+enddate+";");
    ArrayList<Double> data = new ArrayList<Double>();
    while(rs.next()) {
        data.add(rs.getDouble("open"));
    }
    double[] data1 = new double[data.size()];
    for(int a = 0; a < data1.length; ++a) {
        data1[a]=data.get(a);
    }
    return data1;
}
Run Code Online (Sandbox Code Playgroud)

这很慢.它使用我的sqlite数据库需要1.5秒.这是读取列的标准方法还是我做错了什么?这是我的应用程序的瓶颈,所以我需要它尽可能快.


编辑:谢谢.我刚刚发现ArrayList没有引起问题.瓶颈必须在于sql部分:如果我加载数据仅10天就需要加载数据10年.所以我必须改进我的SQL,但如何?

这里改进了代码:

public static double[] open(Connection conn,String symbol,int startdate,int enddate) throws SQLException {
    int id = database.get_stockid(conn, symbol);

    PreparedStatement stat = conn.prepareStatement("select price_open from stock_data where (stock_id="+id +") and (date between "+startdate+" and "+enddate+");");
    ResultSet rs = stat.executeQuery();
    ArrayList<Double> data = new ArrayList<Double>();
    while(rs.next()) {
        data.add(rs.getDouble(1));
    }
    double[] data1 = new double[data.size()];
    for(int a = 0; a < data1.length; ++a) {
        data1[a]=data.get(a);
    }
    return data1;
}
Run Code Online (Sandbox Code Playgroud)

Ada*_*ion 5

  1. 更换

    double[] data1 = new double[data.size()];
    for(int a = 0; a < data1.length; ++a) {
        data1[a]=data.get(a);
    }
    
    Run Code Online (Sandbox Code Playgroud)

    double[] data1 = data.toArray(new double[data.size()]);
    
    Run Code Online (Sandbox Code Playgroud)
  2. 检查查询运行时间是什么(通过分析此应用程序或将日志投入数据库端),检查是否可以通过在where子句id stock_id和中使用的列上引入索引来减少它date.

  3. 如果您能够估计查询将返回的记录数量,或者您知道它将至少为N条记录,则代替:

    ArrayList<Double> data = new ArrayList<Double>();
    
    Run Code Online (Sandbox Code Playgroud)

    引用:

    ArrayList<Double> data = new ArrayList<Double>(AMOUNT_OF_RECORDS);
    
    Run Code Online (Sandbox Code Playgroud)

    这将允许防止扩展ArrayList(创建一个更大的新数组并将元素从较小的数组复制到新的更大的数组).

    BTW.对于ArrayList该类,默认初始容量为10.

  4. 从您的查询返回的结果是唯一的吗?也许从查询返回的大多数值都是重复的?如果是,则将DISTINCT关键字附加到查询中:

    select distinct price_open from stock_data ...
    
    Run Code Online (Sandbox Code Playgroud)

    这样可以节省与数据库通信的时间,并且返回的结果也更少,必须处理的结果更少.

  5. 使用PreparedStatement而不是Statement:

    • 防止SQL注入
    • 但也因为性能,因为使用PreparedStatement允许数据库重用已经解析的查询

更新#1

  1. 记住永远释放所有资源,id ResultSetPreparedStatement.
    • 在Java 1.7+中,您可以使用新的try-with-resources语句(Java®语言规范)
    • 在较旧的Java版本中,您必须对块中的close方法进行调用,finally并为每个调用分别进行异常处理,以防止在第一个调用中发生异常时close阻止第二个close调用的方案.