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 インジェクションから保護する
    • PreparedStatementを使用すると、データベースは既に解析されたクエリを再利用できるため、パフォーマンスのためでもあります。

更新 #1

  1. idと. _ _ResultSetPreparedStatement
    • Java 1.7+ では、新しい try-with-resources ステートメント ( The Java® Language Specification )を使用できます。
    • 古い Java バージョンでは、closeメソッドへの呼び出しをfinallyブロックに配置し、呼び出しごとに個別の例外処理を行って、最初にスローされた例外closeによって 2 番目の呼び出しが妨げられるというシナリオを防ぐ必要がありました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)。これらはクエリで参照される 3 つの列のみであるため、インデックスは元のデータ ページをロードしなくてもクエリを満たすことができます。

于 2013-05-25T23:15:08.373 に答える
1

ArrayList の代わりにプリミティブ配列を使用するとパフォーマンスを向上させることができますが、これには結果セットの大きさを知っている必要があります。

名前ではなくインデックスで列を参照してください。これにより、わずかな改善が得られる場合もあります。

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