2012-05-28 5 views
1

나는이 문제를 몇 달 전에 보았고 지금은 다시 돌아갈 시간이다.안드로이드 - sqlite 테이블 채우기가 오래 걸린다

전화의 콜 로그를 데이터베이스에 쿼리하지만 테이블을 채우는 데 30 초 정도 걸립니다. 질의에 1 초 정도 걸리는 것처럼 보이지만 전화가 마지막 500 건만 저장되지만 인구는 영원히 걸립니다. 왜 그렇게 느린가요? 내가 뭔가 잘못하고 있는거야?

필자는 에뮬레이터의 콜 로그에 단 8 개의 항목 만 가지고 있기 때문에 필자는 필자의 전화에서만 테스트를 실시합니다.

public long populate_Calls(String name, String phone, String type, String duration, String date, String contactid) { 
     ContentValues cv = new ContentValues(); 
     cv.put(KEY_NAME, name); 
     cv.put(KEY_PHONE, phone); 
     cv.put(KEY_TYPE, type); 
     cv.put(KEY_DURATION, duration); 
     cv.put(KEY_DATE, date); 
     cv.put(KEY_CONTACTID, contactid); 
     return ourDatabase.insert(DATABASE_TABLE, null, cv);   
    } 

편집 :

final String[] projection = null; 

      HotOrNot infoA = new HotOrNot(Charts.this); 
      infoA.open(); 
      infoA.createtable_Calls(); 
      infoA.deleteAllEntries_Calls(); 
      infoA.close(); 

      final Context context = getApplicationContext(); 
      final String selection = null; 
      final String sortOrder = android.provider.CallLog.Calls.DATE + " DESC"; 

      Cursor c = context.getContentResolver().query(android.provider.CallLog.Calls.CONTENT_URI, projection, selection, null, sortOrder); 
      while (c.moveToNext()) { 
       String callLogID = c.getString(c.getColumnIndex(android.provider.CallLog.Calls._ID)); 

       int numberColumn = c.getColumnIndex(android.provider.CallLog.Calls.NUMBER); 
       int dateColumn = c.getColumnIndex(android.provider.CallLog.Calls.DATE); 
       int typeColumn = c.getColumnIndex(android.provider.CallLog.Calls.TYPE); 
       int durationColumn = c.getColumnIndex(android.provider.CallLog.Calls.DURATION); 
       int person = c.getColumnIndex(android.provider.CallLog.Calls.CACHED_NAME); 



       String number = c.getString(numberColumn); 
       int duration = c.getInt(durationColumn); 
       String personname = c.getString(person); 
       long callDate = c.getLong(dateColumn); 
       int callType = c.getInt(typeColumn); 

       if (duration >= 0) 
       { 
        switch (callType) { 
        case 1: 
         duration_in = duration; 
         duration_out = 0; 
         break; 
        case 2: 
         duration_out = duration; 
         duration_in = 0; 
         break; 
        case 3: 
         duration_in = 0; 
         duration_out = 0; 
         break; 


        } 
        } 

    //Here comes the slow part 

        HotOrNot info = new HotOrNot(Charts.this); 
        info.open(); 
        info.pop 
ulate_Calls(personname, number, String.valueOf(callType), Integer.toString(duration), Long.toString(callDate), callLogID); 
       info.close(); 
      } 

는 채우기 기능입니다

안드레아스 카의 및 twaddington의 답변을 제가 SQLiteOpenHelper 클래스의 인구 방법을 수정,하지만 불행히도 그것은하지 않았다 차이 :

public long populate_Calls(String name, String phone, String type, String duration, String date, String contactid) { 
    ContentValues cv = new ContentValues(); 
    try { 
     ourDatabase.beginTransaction(); 

     cv.put(KEY_NAME, name); 
     cv.put(KEY_PHONE, phone); 
     cv.put(KEY_TYPE, type); 
     cv.put(KEY_DURATION, duration); 
     cv.put(KEY_DATE, date); 
     cv.put(KEY_CONTACTID, contactid); 

     ourDatabase.yieldIfContendedSafely(); 

     ourDatabase.setTransactionSuccessful(); 
    } finally { 
     ourDatabase.endTransaction(); 
    } 

    return ourDatabase.insert(DATABASE_TABLE, null, cv);   
} 

EDIT2 : Babibu와 twaddington의 답변을 기반으로 전체 코드를 게시합니다. 그건 그렇고 temp_ 배열은 이제 LinkedLists지만 시간에 차이가 없다.

final String[] projection = null; 
     final Context context = getApplicationContext(); 
     final String selection = null; 
     final String sortOrder = android.provider.CallLog.Calls.DATE + " DESC"; 
     lv1 = (ListView) findViewById(R.id.ListView02); 


     HotOrNot infoA = new HotOrNot(Calllogs.this); 
     infoA.open(); 
     infoA.createtable_Calls(); 
     infoA.deleteAllEntries_Calls(); 
     infoA.close(); 

      pd = ProgressDialog.show(Calllogs.this, "Please wait..", "Loading data, it may take a few" + 
       " seconds based on the number of data.", false, true); 

     Cursor c = context.getContentResolver().query(android.provider.CallLog.Calls.CONTENT_URI, projection, selection, null, sortOrder); 
     while (c.moveToNext()) { 
      String callLogID = c.getString(c.getColumnIndex(android.provider.CallLog.Calls._ID)); 

      int numberColumn = c.getColumnIndex(android.provider.CallLog.Calls.NUMBER); 
      int dateColumn = c.getColumnIndex(android.provider.CallLog.Calls.DATE); 
      int typeColumn = c.getColumnIndex(android.provider.CallLog.Calls.TYPE); 
      int durationColumn = c.getColumnIndex(android.provider.CallLog.Calls.DURATION); 
      int person = c.getColumnIndex(android.provider.CallLog.Calls.CACHED_NAME); 



      String number = c.getString(numberColumn); 
      int duration = c.getInt(durationColumn); 
      String personname = c.getString(person); 
      long callDate = c.getLong(dateColumn); 
      int callType = c.getInt(typeColumn); 

      if (duration >= 0) 
      { 
       switch (callType) { 
       case 1: 
        duration_in = duration; 
        duration_out = 0; 
        break; 
       case 2: 
        duration_out = duration; 
        duration_in = 0; 
        break; 
       case 3: 
        duration_in = 0; 
        duration_out = 0; 
        break; 
       } 
      } 

      temp_name.add(personname); 
      temp_num.add(number); 
      temp_type.add(String.valueOf(callType)); 
      temp_dur.add(Integer.toString(duration)); 
      temp_date.add(String.valueOf(callDate)); 
      temp_id.add(callLogID); 
      } //end of while loop 


     HotOrNot infotemp = new HotOrNot(Calllogs.this); 
     infotemp.open(); 


      for (int i=0; i<temp_name.size(); i++) 
      { 
       infotemp.populate_Calls(temp_name.get(i), temp_num.get(i), temp_type.get(i), temp_dur.get(i), temp_date.get(i), temp_type.get(i)); 
      } 
infotemp.close(); 

솔루션

나는 미만이 8 초에서 시간을 감소 twaddington의 솔루션, 게시하고있다 : 당신이 SQLite 데이터베이스 A를 만드는 각 변경의 경우

HotOrNot infotemp = new HotOrNot(Calllogs.this); 
     infotemp.open(); 

     // Get our database. You can do this however you wish, but 
     // it seems like since the database is contained in your `HotOrNot` 
     // object, it would be best to simply add a getter method to 
     // the class. 
     SQLiteDatabase db = infotemp.getDatabase(); 

     try { 
      // Begin our transaction 
      db.beginTransaction(); 

      // Loop over the array of calls and 
      // perform a db insert for each. 
      for (int i=0; i<temp_name.size(); i++) { 
       // Yield the database lock if requested. This will 
       // temporarily suspend our loop, but it should 
       // continue when the lock is opened. 
       db.yieldIfContendedSafely(); 

       infotemp.populate_Calls(temp_name.get(i), temp_num.get(i), 
         temp_type.get(i), temp_dur.get(i), temp_date.get(i), temp_type.get(i)); 
      } 

      // Mark our transaction as successful! 
      db.setTransactionSuccessful(); 
     } finally { 
      // Always end the transaction! 
      db.endTransaction(); 
     } 

     infotemp.close(); 
+1

어려운 문제의 정확한 원인을 찾기 위해 Traceview를 사용하십시오. – CommonsWare

+0

다음 번에 나를 위해 계산하십시오 : 'c.moveToNext()', while 루프 전체 시간, 'infotemp.open()', 'infotemp.populate_Calls', 전체 for 루프 시간 –

+0

업데이트 된 코드를 포함 해 주셔서 감사합니다! – twaddington

답변

2

을 일련의 복잡한 단계가 발생합니다. 오류가 발생하면 변경을 롤백하기 위해 journal file을 생성합니다. 데이터베이스 트랜잭션에서 일련의 업데이트를 래핑하면 SQLite가 전체 시리즈를 단일 작업으로 처리하도록 할 수 있습니다. 이것은 훨씬 더 효율적입니다.

try { 
    db.beginTransaction(); 
    while (c.moveToNext()) { 
     // Yield the database lock if requested 
     db.yieldIfContendedSafely(); 

     // Add your code here! 
     // ... 

     // Perform the database insert 
     populate_Calls(...); 
    } 
    db.setTransactionSuccessful(); 
} finally { 
    db.endTransaction(); 
} 
+0

나는 내 메인 포스트를 편집했다. 내가 잘못했는지 확인해 줄래? 나는 이것이 어디서나 삽입을 가속화하지만, 내 경우 엔 그렇지 않다. – erdomester

+0

populate 메소드를 호출하는 루프 외부로 트랜잭션을 넣어야한다. 당신이 지금 가지고있는 방식, 그것은 전혀 다른 일을하지 않습니다. 그것은 여전히 ​​각 삽입물에 대해 하나의 트랜잭션을 수행하고 있습니다. 원하는 것은 모든 삽입에 대해 단일 트랜잭션입니다. 위에 게시 한 예제를 살펴보면 트랜잭션이 루프 외부에서 시작 및 끝나는 것을 알 수 있습니다. – twaddington

+0

나는 당신을 이해하고 있는지 잘 모르겠습니다. 논리 (많은 것 대신에 하나의 변환)를 이해하지만 코드를 변경하는 방법을 모르겠습니다. – erdomester

1

. while 루프를 끝내고 데이터베이스에 삽입해야합니다. 동일한 임시 연결 목록에 데이터를 보관하십시오 (귀하의 경우에는 배열이 더 빠릅니다).

+0

그는 다른 데이터베이스에서 읽고 쓰고 있습니다. 당신은 이것이 일반적으로 나쁜 생각 인 것이 맞지만 여기서는 어떤 문제도 일으키지 않는다고 생각합니다. 오히려 주요 문제는 거래에서 인서트를 감쌀 필요가 있다는 것입니다. – twaddington

+0

@twaddington 그 시대는 불가능합니다. 확실히 잠겨 있습니다. 그리고 거래는 그만큼 비용이 많이들 수 있습니다 ... 나는 문제를 집중시키는 것만 큼 어떤 방식 으로든 나누는 것이 좋습니다. 누가 안드로이드 버그 일지 모른다 ... –

+1

하나의 데이터베이스와 하나의 테이블을 사용하고 있습니다. 나는 이것을 시도하고 28 초에서 7 초로 시간을 단축했다. – erdomester

관련 문제