4

我试图从 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;
}

这很慢。我的 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;
}
4

3 回答 3

5
  1. 代替

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

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

  3. 如果您能够估计您的查询将返回的记录数量,或者您知道它将至少有 N 条记录,那么而不是:

    ArrayList<Double> data = new ArrayList<Double>();
    

    调用:

    ArrayList<Double> data = new ArrayList<Double>(AMOUNT_OF_RECORDS);
    

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

    顺便提一句。对于ArrayList该类,默认初始容量为 10。

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

    select distinct price_open from stock_data ...
    

    这将节省与数据库通信的时间,并且返回的结果更少,需要处理的结果也更少。

  5. 使用PreparedStatement而不是Statement

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

更新#1

  1. 请记住始终释放所有资源,idResultSetPreparedStatement.
    • 在 Java 1.7+ 中,您可以使用新的 try-with-resources 语句(Java® 语言规范
    • 在较旧的 Java 版本中,您必须对块中的close方法进行调用,finally并对每个调用进行单独的异常处理,以防止出现第一次抛出的异常close阻止调用第二次close的情况。
于 2013-05-25T20:07:36.183 回答
2

您的查询是:

select price_open
from stock_data
where stock_id="+id+" and date>="+startdate+" and date<="+enddate+"

要优化这一点,请在stock_data(stock_id, date). 索引查找将用于获取数据。

如果您的数据真的很大,那么您可以将索引放在stock_data(stock_id, date, price_open). 这些是查询中唯一引用的三列,因此索引可以满足查询而无需加载原始数据页。

于 2013-05-25T23:15:08.373 回答
1

您可以通过使用原始数组而不是 ArrayList 来提高性能,但这需要您知道结果集有多大。

通过索引而不是名称来引用列 - 这也可以提供轻微的改进。

 datars.getDouble(1);
于 2013-05-25T21:37:03.063 回答