2012-02-16 20 views
0

この質問がここにあるのかどうかはわかりませんが、皆さんにお聞きしたいのですが、このコードを最適化する方法のアドバイス適切な方法でより速く実行することができます。私がやっていることは、インターネット上でJSONとしてデータをダウンロードし、解析してsqliteデータベースに挿入することです。 json文字列が大きければ大きな問題はありませんが、私のjsonにはいくつかの状況で多くの配列とオブジェクトが含まれていて、データベースのすべてのデータをダウンロード/解析/挿入するために10-13分かかるのを待っていますこれはあまりにも時間がかかる。Android Java JSONパーサ/データベースの最適化

私が表示しているコードは、速度に少し違いがあるかどうかを確認するためにInsertHelperを実装しようとしていたため、テストコードのようなものですが、結果は今のところ同じです。ここでは、コードは次のようになります。

UserDatabaseHelper userDbHelper = RPCCommunicator.rpcUserDbHelper; 

    SQLiteDatabase db = userDbHelper.getWritableDatabase(); 
    InsertHelper ih = new InsertHelper(db, "cards"); 

    ih.prepareForInsert(); 
    //ContentValues values = new ContentValues(); 
    ContentValues valuess = new ContentValues(); 
    try { 
     int objectid = ih.getColumnIndex("objectId"); 
     ih.bind(objectid, objectId); 
     //values.put("objectId", objectId); 
     Log.d("", "ObjectId: " + objectId); 
     int objectoid = ih.getColumnIndex("objectOid"); 
     ih.bind(objectoid, objectOid); 
     //values.put("objectOid", objectOid); 

     String jsonData = new String(cardBuffer, "UTF-8"); 
     Log.d("JSONDATA", "JSONDATA VALID OR NOT : " + jsonData); 
     json = new JSONObject(jsonData); 
     JSONObject jsonObj = (JSONObject) new JSONTokener(jsonData).nextValue(); 

     int collectionID = ih.getColumnIndex("collectionId"); 
     int collectionId = Integer.parseInt(jsonObj.optString("collection_id","0")); 
     Log.d("Collection Id ", "Show Collection Id : " + collectionId); 
     if(collectionId!=0) 
      ih.bind(collectionID, collectionId); 

     //values.put("collectionId", collectionId); 

     int categoryID = ih.getColumnIndex("categoryId"); 
     int categoryId = Integer.parseInt(jsonObj.optString("category_id", "0")); 
     Log.d("Category Id ", "Show Category Id : " + categoryId); 
     if(categoryId!=0) 
      ih.bind(categoryID, categoryId); 
     //values.put("categoryId", categoryId); 

     int dateCreated = ih.getColumnIndex("dateCreated"); 
     String date = jsonObj.optString("date_created"); 
     if(date!=null) 
      ih.bind(dateCreated, date); 
     //values.put("dateCreated", date); 

     int titlee = ih.getColumnIndex("title"); 
     String title = jsonObj.optString("title"); 
     Log.d("Title", "Show Title : " + title); 
     if(title!=null) 
      ih.bind(titlee, title); 
     //values.put("title", title); 

     // ... some other variables to get from JSON 

     JSONObject stats = jsonObj.optJSONObject("statistics"); 

     if (jsonObj.has("statistics")) { 
      ContentValues values2 = new ContentValues(); 
      InsertHelper ihr = new InsertHelper(db, "cardstats"); 


      Iterator<Object> keys = stats.keys(); 
      while (keys.hasNext()) { 

       ihr.prepareForInsert(); 
       String key = (String) keys.next(); 
       JSONObject obj = new JSONObject(); 
       obj = stats.getJSONObject(key); 

       int paramId = Integer.parseInt(obj.optString("param_id")); 

       int cardIdTable = ihr.getColumnIndex("cardId"); 
       ihr.bind(cardIdTable, objectId); 

       values2.put("cardId", objectId); 

       int statKey = ihr.getColumnIndex("statKeyId"); 
       ihr.bind(statKey, paramId); 

       values2.put("statKeyId", paramId); 

       int catIdTable = ihr.getColumnIndex("catId"); 
       int catId = Integer.parseInt(obj.optString("cat_id")); 
       ihr.bind(catIdTable, catId); 

       values2.put("catId", catId); 

       int paramtitle = ihr.getColumnIndex("title"); 
       String paramTitle = obj.optString("param_title"); 
       ihr.bind(paramtitle, paramTitle); 

       values2.put("title", paramTitle); 

       String cardstats = "SELECT cardId , statKeyId FROM cardstats WHERE cardId="+objectId+" AND statKeyId="+catId; 
       Cursor cardStats = userDbHelper.executeSQLQuery(cardstats); 
       if(cardStats.getCount()==0){ 
        //userDbHelper.executeQuery("cardstats", values2); 
        ihr.execute(); 
       } else { 
        for(cardStats.moveToFirst(); cardStats.moveToNext(); cardStats.isAfterLast()){ 
         //int card = Integer.parseInt(cardStats.getString(cardStats.getColumnIndex("cardId"))); 
         int statId = Integer.parseInt(cardStats.getString(cardStats.getColumnIndex("statKeyId"))); 

         if(paramId != statId){ 
          ihr.execute(); 
          //userDbHelper.executeQuery("cardstats", values2); 
         } else { 
          userDbHelper.updateSQL("cardstats", values2, "cardId=?", new String[]{Integer.toString(objectId)}); 
         } 
        } 
       } 
       cardStats.close(); 

       //userDbHelper.executeQuery("cardstats", values2); 
      } 
     }// end if 

     String sql = "SELECT objectId FROM cards WHERE objectId = " + objectId; 
     Cursor cursor = userDbHelper.executeSQLQuery(sql); 
     if (cursor.getCount() == 0) { 
      ih.execute(); 
      //userDbHelper.executeQuery("cards", values); 
     } else { 
      for (cursor.move(0); cursor.moveToNext(); cursor.isAfterLast()) { 
       int objectID = Integer.parseInt(cursor.getString(cursor.getColumnIndex("objectId"))); 
       Log.d("","objectId : objectID - "+objectId+" "+objectID); 
       if (objectId != objectID) { 
        ih.execute(); 
        //userDbHelper.executeQuery("cards", values); 
       } else if(objectId == objectID){ 
        userDbHelper.updateSQL("cards", valuess, "objectId=?", new String[] {Integer.toString(objectId)}); 
       } 
      } 
     } 
     cursor.close(); 

    } catch (Exception e) { 
     e.printStackTrace(); 
     Log.d("Error", ": " + e); 
    } 
    db.close(); 
    return true; 
} 

* 編集:*

そして、ここで私は、バイナリデータを保存する方法である私は、インターネットから取得する(画像):

public static void saveToExternalStorage(String servername, int userId, String filename, byte[] buffer){ 
    try { 
     File myDir=new File("/sdcard/.Stampii/Users/"+servername+"/"+userId+"/Storage"); 
     myDir.mkdirs(); 

     File file = new File(myDir, filename); 
     FileOutputStream fos = new FileOutputStream(file); 
     fos.write(buffer); 
     fos.flush(); 
     fos.close(); 

    } catch (FileNotFoundException e){ 
     e.printStackTrace(); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

だから、どのような種類は、提案/アドバイスが歓迎され、このコードを改善してより速く実行できるようになります。

ありがとうございます!

+0

トランザクションで大きなチャンク( 'SQLiteDatabase#beginTransaction()')を実行しようとすると、何がパフォーマンスになりますか?たとえば、100-300の挿入/更新はポップですか? – Jens

+0

実際に私がダウンロードしている1つのパケットには250個の挿入物があり、200個のパケットが入っています。ですから、ContentValuesやInsertHelperを使用すると、その差は今のところ10〜15秒です。 –

+0

さて、SQLトランザクションを開始すると、「通常の」挿入と最適化されたInsertHelperの両方に影響します。おそらくテストが必要な速度に影響する場合。単純にデータをダウンロードして解析するのと比較して、SQLiteで実際に費やした時間はどれくらいですか? – Jens

答えて

1

あなたのケースには2つの時間がかかります。

a。データをパケットでダウンロードする(HTTPと仮定して) 1パケットの場合は、ネットワークの待ち時間に応じて約1〜3秒かかります。 200 = 2X100 = 200秒〜3分 3〜5回以内の往復呼び出しでデータ全体をダウンロードすると、秒を大幅に節約できます。

b。データベースの挿入 あなたは時間がかかるファイル操作を特に書き込み操作を行う必要があります。正直なところ、あなたがここに多くの最適化をすることはできません

あなたは(あなたが持っているように見えた)HTTPトラフィックの多くを持っている場合でも、あなたはまだデータベースの使用を最適化することができます私の他の答えhere

+0

実際、最後の数パケットはバイナリデータです。私はSDカードに保存していますが、保存する最良の方法についてはアドバイスを受けています。私はSDCardにそれらを書いている関数で私の答えを編集します。 –

+0

画像を保存する方法がよく見えます。これをAsyncTaskに配置し、バックグラウンドで実行することとは別に、改善するためにできることはあまりありません。 – PravinCG

+1

@Bombastic:外部ストレージに書き込むときに、パスに "/ sdcard"を絶対にハードコードしないでください。その前に 'Environment#getExternalStorageDirectory()'を試してみてください。 – Jens

2

を確認してください。 10000個の挿入を行い

このナイーブ例では、私たちがここで話しているあなたに改善のスケールが表示されます:あなたがスレッドまたはスレッドプールを開始した場合

public class BombasticActivity extends Activity { 
    DBHelper mHelper; 
    SQLiteDatabase mDb; 
    InsertHelper mInsertHelper; 
    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.main); 
     mHelper = new DBHelper(this); 
     mDb = mHelper.getWritableDatabase(); 
     mInsertHelper = new InsertHelper(mDb, "table1"); 
    } 
    @Override 
    protected void onStart() { 
     super.onStart(); 
     AsyncTask.SERIAL_EXECUTOR.execute(new MeasureTime(new Insert(10000, mInsertHelper))); 
     AsyncTask.SERIAL_EXECUTOR.execute(new MeasureTime(new DoInTransaction(mDb, new Insert(10000, mInsertHelper)))); 
    } 
    @Override 
    protected void onDestroy() { 
     super.onDestroy(); 
     mInsertHelper.close(); 
     mDb.close(); 
     mHelper.close(); 
    } 
    static class MeasureTime implements Runnable { 
     final Runnable mAction; 
     MeasureTime(Runnable action) { 
      mAction = action; 
     } 
     public void run() { 
      final String name = mAction.getClass().getSimpleName(); 
      System.out.println("Starting action (" + name + ")"); 
      long t0 = System.currentTimeMillis(); 
      try { 
       mAction.run(); 
      } finally { 
       t0 = System.currentTimeMillis() - t0; 
       System.out.println("Time to complete action (" + name + "): " + t0 + "ms"); 
      } 
     } 
    } 
    static class DoInTransaction implements Runnable { 
     final Runnable mAction; 
     final SQLiteDatabase mDb; 
     DoInTransaction(SQLiteDatabase db, Runnable action) { 
      mAction = action; 
      mDb = db; 
     } 
     public void run() { 
      mDb.beginTransaction(); 
      try { 
       mAction.run(); 
       mDb.setTransactionSuccessful(); 
      } finally { 
       mDb.endTransaction(); 
      } 
     } 
    } 
    static class Insert implements Runnable { 
     final int mNumberOfInserts; 
     final InsertHelper mInsertHelper; 
     Insert(int numberOfInserts, InsertHelper insertHelper) { 
      mNumberOfInserts = numberOfInserts; 
      mInsertHelper = insertHelper; 
     } 
     public void run() { 
      Random rnd = new Random(0xDEADBEEF); 
      ContentValues values = new ContentValues(); 
      for (int i = 0; i < mNumberOfInserts; i++) { 
       values.put("text1", String.valueOf(rnd.nextDouble())); 
       values.put("text2", String.valueOf(rnd.nextFloat())); 
       values.put("text3", String.valueOf(rnd.nextLong())); 
       values.put("int1", rnd.nextInt()); 
       mInsertHelper.insert(values); 
       if (i % 200 == 0) { 
        System.out.println("Done " + i + " inserts"); 
       } 
      } 
     } 
    } 
} 

class DBHelper extends SQLiteOpenHelper { 
    DBHelper(Context context) { 
     super(context.getApplicationContext(), "bombastic", null, 1); 
    } 
    @Override 
    public void onCreate(SQLiteDatabase db) { 
     db.execSQL("CREATE TABLE table1 (_id INTEGER PRIMARY KEY AUTOINCREMENT, text1 TEXT, text2 TEXT, text3 TEXT, int1 INTEGER)"); 
    } 
    @Override 
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
    } 
} 

ICSデバイス上で(あなたはジンジャーブレッドでそれを実行することができます非トランザクションのバージョンは約4分(229484ms)、トランザクションのバージョンは約3秒(2975ms)しかかかりません。

すぐに言えば、多くの更新を行います。これをトランザクションで実行します。

HTTPを最適化するには、HTTP接続をアクティブ(キープアライブ)に保ち、より大きなチャンクをダウンロードする必要があります。可能な場合は、解析する前にストリーム全体を読み込むのではなく、ストリームからの読み込みをサポートするJSONパーサに切り替えてください(String)。

関連する問題