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

标签 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;
}

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

最佳答案

  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 子句 i.d. 中使用的列上引入索引。 stock_iddate

  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注入(inject)
    • 还因为性能,因为使用 PreparedStatement 允许数据库重用已经解析的查询

更新 #1

  1. 记住总是释放所有资源,i.d. ResultSetPreparedStatement
    • 在 Java 1.7+ 中,您可以使用新的 try-with-resources 语句 ( The Java® Language Specification )
    • 在旧的 Java 版本中,您必须在 finally block 中调用 close 方法,并对每个调用进行单独的异常处理,以防止出现异常情况在第一个 close 中抛出会阻止调用第二个 close

关于Java:如何有效地从数据库中读取?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16753434/

相关文章:

java - Spring Boot应用程序内存消耗

sql - 从sql中的字符串中提取数字并进行计算

mysql - 像这样在 SQL 查询中查找 SQL 表和列表之间的公共(public)值

ios - 有没有办法检查 Objective-c 提供的方法的时间复杂度?

Android - E/Surface:queueBuffer : error queuing buffer to SurfaceTexture, -22 崩溃

java - 如何在 session 范围 bean 中模拟请求范围行为?

java - 为什么我的循环没有在满足特定条件时结束?

java - 如何让 Maven 下载构建所需的任何文件?

sql - MySQL查询返回等于或大于某个日期的行,其中日期以年、月、日列分隔

jquery - Javascript jQuery 将大段代码插入 DOM 的最佳方式