1

デバイスの機能をテストしています。デバイス内に保存できるデータのサイズ、データの取得速度、検索の速度などを顧客に示します。

コンテンツ プロバイダを使用して、product列数の少ないデータベース テーブルにアクセスしています。テスト レコードを挿入する際の余分な通信を避けるために、コードは既にコンテンツ プロバイダーに移動しています。次のコードは、アクティビティからメニューを介して呼び出され、テーブルにテスト コンテンツを入力します。

Uri uri = Uri.parse(DemoContentProvider.PRODUCTS_CONTENT_URI + "/insertdemo");
getContentResolver().insert(uri, null);

URI はコンテンツ プロバイダーのメソッドで認識され、.insert(同じコンテンツ プロバイダーの) 次のプライベート メソッドが呼び出されてテーブルに入力されます (10 万のアイテムに注意してください)。

private void insertDemoProducts() {
    for (int i = 1; i <= 100000; ++i) {
        String id = Integer.toString(i);
        insertProduct(id, "Test product " + id, "100", "75.50", "70.27");
    }
}

内部insertProduct()は次のようになります。

private void insertProduct(String code, String name, String stock,
                           String price,  String listprice) {
    SQLiteDatabase sqlDB = database.getWritableDatabase();
    ContentValues values = new ContentValues();

    values.put(ProductTable.COLUMN_CODE, code);
    values.put(ProductTable.COLUMN_NAME, name);
    values.put(ProductTable.COLUMN_STOCK, stock);
    values.put(ProductTable.COLUMN_PRICE, price);
    values.put(ProductTable.COLUMN_LISTPRICE, listprice);

    sqlDB.insert(ProductTable.TABLE_PRODUCT, null, values);
}

機能しますが、 「永遠に」かかります。どうすれば速くなりますか?テーブルを埋めるための、あなたが知っている最速の方法は何ですか?

考慮すべきいくつかの数字: 1000 個のアイテムの作成には約 20 秒かかります。

4

2 に答える 2

1

sqlite-database に書き込むときはトランザクションを使用する必要があります。そうしないと、挿入ごとにデータが永続化されます。つまり、sd に保存されますが、これには「永久に」時間がかかります。

たとえば、insertProduct が製品のリストを取得し、それらを 1 つのトランザクションで保存するようにします。

private void insertProducts(List<Product> products) {
    try {
        db.beginTransaction();
        for(Product product : products) {
            insertProduct(...);
        }
        db.setTransactionSuccessful();
    } finally {
        db.endTransaction();
    }
}

これは、既存のコードに実装する方法です。

private void insertDemoProducts() {
    SQLiteDatabase sqlDB = database.getWritableDatabase();
    try {
        sqlDB.beginTransaction();
        for (int i = 1; i <= 100000; ++i) {
            String id = Integer.toString(i);
            insertProduct(id, "Test product " + id, "100", "75.50", "70.27");
        }
        sqlDB.setTransactionSuccessful();
    } finally {
        sqlDB.endTransaction();
    }
}
于 2013-05-27T14:28:37.583 に答える
0

とにかく、トランザクションを追加すると処理が速くなる理由が理解できないため、受け入れられた質問に完全に満足しているわけではありません。

Android のソースを見ると、sqlDB.insert(...)呼び出しと、クラスinsertWithOnConflict(...)を使用して SQL コマンドの文字列を作成していることがわかりました (挿入された値のプレースホルダーとして疑問符を使用)。その場合にのみ、文字列は挿入された値の配列とともにコンストラクターにStringBuilder渡されます。SQLiteStatementこれは、SQL コマンドを含む文字列が何度も作成されていることを意味します。

さらに、SQL コマンド テンプレートの文字列表現をプリコンパイルできるため、コマンドのコンパイルを繰り返す必要もありません。次に.bindXxx.executeメソッドを使用して、必要なレコードをテーブルに挿入できます。まとめると、次のコードを使用しました(ディーンが提案した外部トランザクションの横):

        StringBuilder sql = new StringBuilder();
        sql.append("INSERT INTO ");
        sql.append(ProductTable.TABLENAME);
        sql.append("(");
        sql.append(ProductTable.COLUMN_CODE);
        sql.append(",");
        sql.append(ProductTable.COLUMN_NAME);
        sql.append(",");
        sql.append(ProductTable.COLUMN_STOCK);
        sql.append(",");
        sql.append(ProductTable.COLUMN_PRICE);
        sql.append(",");
        sql.append(ProductTable.COLUMN_LISTPRICE);
        sql.append(") VALUES (?, ?, 100, 75.50, 70.27)");

        SQLiteStatement insert = sqldb.compileStatement(sql.toString());

        for (int i = 1; i <= 300000; ++i) {
            insert.bindLong(1, i);
            insert.bindString(2, "Test product " + i);
            insert.execute();
        }

トランザクションのみを追加する場合と比較すると、結果は約 3 倍速くなります。Nexus 7 では約 3 分 15 秒で 30 万件のレコードが挿入されました。

于 2013-05-28T13:24:11.150 に答える