android - एंड्रॉइड SQLite डेटाबेस: धीमी प्रविष्टि
database performance (4)
आपको बैच आवेषण करना चाहिए।
स्यूडोकोड:
db.beginTransaction();
for (entry : listOfEntries) {
db.insert(entry);
}
db.setTransactionSuccessful();
db.endTransaction();
इससे मेरे ऐप्स में इन्सर्ट की गति में अत्यधिक वृद्धि हुई।
अद्यतन करें:
@Yuku ने एक बहुत ही रोचक ब्लॉग पोस्ट प्रदान किया: स्क्वाइट डेटाबेस में तेजी से सम्मिलन के लिए एंड्रॉइड का उपयोग करके एंड्रॉइड का उपयोग करना
मुझे एक बड़ी बड़ी एक्सएमएल फ़ाइल (लगभग सौ किलोबाइट्स और कई सौ किलोबाइट्स के बीच बदलती है) को पार्स करने की ज़रूरत है, जिसे मैं Xml#parse(String, ContentHandler)
का उपयोग कर कर रहा हूं। मैं वर्तमान में इसे 152 केबी फ़ाइल के साथ परीक्षण कर रहा हूं।
पार्सिंग के दौरान, मैं निम्नलिखित के समान कॉल का उपयोग कर SQLite डेटाबेस में डेटा भी getWritableDatabase().insert(TABLE_NAME, "_id", values)
: getWritableDatabase().insert(TABLE_NAME, "_id", values)
। इसमें से सभी को 152 केबी परीक्षण फ़ाइल के लिए लगभग 80 सेकंड लगते हैं (जो लगभग 200 पंक्तियों को सम्मिलित करने के लिए नीचे आता है)।
जब मैं सभी सम्मिलित बयानों पर टिप्पणी करता हूं (लेकिन अन्य सभी चीज़ों में छोड़ देता हूं, जैसे ContentValues
आदि बनाना) उसी फ़ाइल में केवल 23 सेकंड लगते हैं।
क्या डाटाबेस ऑपरेशंस के लिए इतना बड़ा ओवरहेड होना सामान्य है? क्या मैं इसके बारे में कुछ कर सकता हूँ?
एसक्यूएल सम्मिलन कथन को संकलित करने से गति की चीजों में मदद मिलती है। इसे सबकुछ किनारे लगाने और संभावित इंजेक्शन को रोकने के लिए और अधिक प्रयास की आवश्यकता हो सकती है क्योंकि अब यह आपके कंधों पर है।
एक अन्य दृष्टिकोण जो चीजों को गति दे सकता है वह अंडर-डॉक्यूमेंटेड android.database.DatabaseUtils.InsertHelper क्लास है। मेरी समझ यह है कि यह वास्तव में संकलित सम्मिलित बयान लपेटता है। संकलित ट्रांस्ड किए गए आवेषणों के लिए गैर-संकलित ट्रांस्ड किए गए आवेषणों से जाकर मेरे बड़े (200 के + प्रविष्टियों) के लिए गति में 3x लाभ (प्रति दिन 2 एमएमएस प्रति डालने) के बारे में था, लेकिन सरल SQLite आवेषण।
नमूना कोड:
SQLiteDatabse db = getWriteableDatabase();
//use the db you would normally use for db.insert, and the "table_name"
//is the same one you would use in db.insert()
InsertHelper iHelp = new InsertHelper(db, "table_name");
//Get the indices you need to bind data to
//Similar to Cursor.getColumnIndex("col_name");
int first_index = iHelp.getColumnIndex("first");
int last_index = iHelp.getColumnIndex("last");
try
{
db.beginTransaction();
for(int i=0 ; i<num_things ; ++i)
{
//need to tell the helper you are inserting (rather than replacing)
iHelp.prepareForInsert();
//do the equivalent of ContentValues.put("field","value") here
iHelp.bind(first_index, thing_1);
iHelp.bind(last_index, thing_2);
//the db.insert() equilvalent
iHelp.execute();
}
db.setTransactionSuccessful();
}
finally
{
db.endTransaction();
}
db.close();
यदि तालिका में एक अनुक्रमणिका है, तो रिकॉर्ड्स डालने से पहले इसे छोड़ने पर विचार करें और फिर अपने रिकॉर्ड करने के बाद इसे वापस जोड़ दें।
यदि सामग्री प्रदाता का उपयोग करना है:
@Override
public int bulkInsert(Uri uri, ContentValues[] bulkinsertvalues) {
int QueryType = sUriMatcher.match(uri);
int returnValue=0;
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
switch (QueryType) {
case SOME_URI_IM_LOOKING_FOR: //replace this with your real URI
db.beginTransaction();
for (int i = 0; i < bulkinsertvalues.length; i++) {
//get an individual result from the array of ContentValues
ContentValues values = bulkinsertvalues[i];
//insert this record into the local SQLite database using a private function you create, "insertIndividualRecord" (replace with a better function name)
insertIndividualRecord(uri, values);
}
db.setTransactionSuccessful();
db.endTransaction();
break;
default:
throw new IllegalArgumentException("Unknown URI " + uri);
}
return returnValue;
}
फिर सम्मिलित करने के लिए निजी फ़ंक्शन (अभी भी आपके सामग्री प्रदाता के अंदर):
private Uri insertIndividualRecord(Uri uri, ContentValues values){
//see content provider documentation if this is confusing
if (sUriMatcher.match(uri) != THE_CONSTANT_IM_LOOKING_FOR) {
throw new IllegalArgumentException("Unknown URI " + uri);
}
//example validation if you have a field called "name" in your database
if (values.containsKey(YOUR_CONSTANT_FOR_NAME) == false) {
values.put(YOUR_CONSTANT_FOR_NAME, "");
}
//******add all your other validations
//**********
//time to insert records into your local SQLite database
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
long rowId = db.insert(YOUR_TABLE_NAME, null, values);
if (rowId > 0) {
Uri myUri = ContentUris.withAppendedId(MY_INSERT_URI, rowId);
getContext().getContentResolver().notifyChange(myUri, null);
return myUri;
}
throw new SQLException("Failed to insert row into " + uri);
}