6

ローカル SQLite DB に挿入するさまざまなバッファー サイズで遊んでいますが、バッファー サイズが 10,000 の場合、10,000,000 行のデータを挿入するのに 8 分近くかかることがわかりました。つまり、すべてを保存するには 1,000 回の書き込みが必要です。

10,000,000 を格納するのに 8 分は少し長すぎるように思えます (それとも?)

以下のいずれかを最適化して速度を上げることはできますか? 挿入されるデータは、文字のランダムなコレクションであることに注意してください。

public int flush() throws SQLException {
    String sql = "insert into datastore values(?,?,?,?);";

    PreparedStatement prep = con.prepareStatement(sql);

    for (DatastoreElement e : content) { // content is 10,000 elements long
        _KVPair kvp = e.getKvp();

        prep.setInt(1, e.getMetaHash());
        prep.setInt(2, kvp.hashCode());
        prep.setString(3, kvp.getKey());
        prep.setString(4, kvp.getValue());

        prep.addBatch();
    }

    int[] updateCounts = prep.executeBatch();

    con.commit();

    return errorsWhileInserting(updateCounts);
}

テーブルが作成されるとき、それは経由で行われます

    statement.executeUpdate("create table datastore 
               (meta_hash INTEGER," + 
               "kv_hash   INTEGER," + 
               "key TEXT," +
               "value TEXT);");

上記のいずれかをさらに最適化できますか?

4

2 に答える 2

13

私は Java API について少しぼんやりしていますが、最初にトランザクションを開始する必要があると思います。それ以外の場合、呼び出しcommit()は無意味です。でそれを行いconn.setAutoCommit(false)ます。そうしないと、SQLite は個々の挿入/更新ごとにジャーナリングを行います。ファイルを同期する必要があるため、速度が低下します。

編集: 質問者は、これは既に true に設定されていると更新しました。その場合:

それはたくさんのデータです。その時間の長さは、この世のものとは思えません。最善の方法は、さまざまなバッファー サイズでテストを行うことです。それらが小さすぎることによるバッファーのジッターと、大きなサイズで起動する仮想メモリとの間のバランスがあります。このため、すべてを一度に 1 つのバッファーに入れないでください。インサートを独自のバッチに分割します。

于 2012-08-23T15:36:10.990 に答える
2

実行executeBatchは 1 回だけです。つまり、1,000 万のステートメントすべてがexecuteBatch呼び出しでデータベースに送信されます。これは、データベースで処理するには多すぎます。int[] updateCounts = prep.executeBatch();さらに、ループ内で 1000 行すべてを実行する必要があります。でテストする if ステートメントを作成するだけcounter % 1000 == 0です。その後、データベースは、送信したデータを非同期で処理できます。

于 2012-08-23T16:05:14.997 に答える