android ApplyBatch का उपयोग करके हजारों संपर्क प्रविष्टियों का सम्मिलन धीमा है




android-contentprovider android-contentresolver (6)

@jcwenger सबसे पहले, आपकी पोस्ट को पढ़ने के बाद, मुझे लगता है कि बल्कइन्टर का कारण ApplyBatch की तुलना में तेज है, लेकिन संपर्क प्रदाता के कोड को पढ़ने के बाद, मुझे ऐसा नहीं लगता। 1. आपने कहा कि ApplyBatch लेनदेन का उपयोग करें, हाँ, लेकिन बल्कइन्टर भी लेनदेन का उपयोग करते हैं। यहाँ इसका कोड है:

public int bulkInsert(Uri uri, ContentValues[] values) {
    int numValues = values.length;
    mDb = mOpenHelper.getWritableDatabase();
    mDb.beginTransactionWithListener(this);
    try {
        for (int i = 0; i < numValues; i++) {
            Uri result = insertInTransaction(uri, values[i]);
            if (result != null) {
                mNotifyChange = true;
            }
            mDb.yieldIfContendedSafely();
        }
        mDb.setTransactionSuccessful();
    } finally {
        mDb.endTransaction();
    }
    onEndTransaction();
    return numValues;
}

कहने का तात्पर्य यह है कि, बल्कइन्टर ट्रांसक्शन का भी उपयोग करते हैं। इसलिए मुझे नहीं लगता कि इसका कारण है। 2. आपने कहा कि थोक व्यापारी एक ही तालिका में मानों का एक पूरा ढेर लागू करता है। मुझे खेद है कि मैं संबंधित कोड froyo के स्रोत कोड में नहीं पा सकता हूं। और मैं जानना चाहता हूं कि आप इसे कैसे ढूंढ सकते हैं? क्या आप मुझे बता सकते हैं?

मुझे लगता है कि कारण है:

बल्क इनवर्टर mDb.yieldIfContendedSafely () का उपयोग करते हैं, जबकि लागू होते हैं mDb.yieldIfContendedSafely (SLEEP_AFTER_YIELD_DELAY) / * SLEEP_AFTER_YIELD_DELAY = 4000 * / का उपयोग करें

SQLiteDatabase.java के कोड को पढ़ने के बाद, मुझे पता चलता है कि अगर यील्ड में एक समय निर्धारित किया जाए, तो यह सो जाएगा, लेकिन यदि आप समय निर्धारित नहीं करते हैं, तो यह नहीं सोएगा। आप नीचे दिए गए कोड का उल्लेख कर सकते हैं SQLiteDatabase.java के कोड का एक टुकड़ा

private boolean yieldIfContendedHelper(boolean checkFullyYielded, long     sleepAfterYieldDelay) {
    if (mLock.getQueueLength() == 0) {
        // Reset the lock acquire time since we know that the thread was willing to yield
        // the lock at this time.
        mLockAcquiredWallTime = SystemClock.elapsedRealtime();
        mLockAcquiredThreadTime = Debug.threadCpuTimeNanos();
        return false;
    }
    setTransactionSuccessful();
    SQLiteTransactionListener transactionListener = mTransactionListener;
    endTransaction();
    if (checkFullyYielded) {
        if (this.isDbLockedByCurrentThread()) {
            throw new IllegalStateException(
                    "Db locked more than once. yielfIfContended cannot yield");
        }
    }
    if (sleepAfterYieldDelay > 0) {
        // Sleep for up to sleepAfterYieldDelay milliseconds, waking up periodically to
        // check if anyone is using the database.  If the database is not contended,
        // retake the lock and return.
        long remainingDelay = sleepAfterYieldDelay;
        while (remainingDelay > 0) {
            try {
                Thread.sleep(remainingDelay < SLEEP_AFTER_YIELD_QUANTUM ?
                        remainingDelay : SLEEP_AFTER_YIELD_QUANTUM);
            } catch (InterruptedException e) {
                Thread.interrupted();
            }
            remainingDelay -= SLEEP_AFTER_YIELD_QUANTUM;
            if (mLock.getQueueLength() == 0) {
                break;
            }
        }
    }
    beginTransactionWithListener(transactionListener);
    return true;
}

मुझे लगता है कि बल्कइंटरेंट का कारण अप्लायबैक से तेज है।

किसी भी प्रश्न कृपया मुझसे संपर्क करें।

मैं एक एप्लिकेशन विकसित कर रहा हूं जहां मुझे बहुत सारी संपर्क प्रविष्टियां सम्मिलित करने की आवश्यकता है। वर्तमान समय में कुल मिलाकर 6000 फोन नंबरों के साथ 600 संपर्क। सबसे बड़े संपर्क में 1800 फोन नंबर हैं।

आज की स्थिति यह है कि मैंने संपर्कों को रखने के लिए एक कस्टम खाता बनाया है, इसलिए उपयोगकर्ता संपर्क दृश्य में संपर्क देखने का चयन कर सकता है।

लेकिन संपर्कों का सम्मिलन दर्दनाक रूप से धीमा है। मैं ContentResolver.applyBatch का उपयोग करके संपर्क सम्मिलित करता हूं। मैंने ContentProviderOperation सूची (100, 200, 400) के विभिन्न आकारों के साथ प्रयास किया है, लेकिन कुल चलने का समय लगभग है। वही। सभी संपर्कों और संख्याओं को सम्मिलित करने के लिए लगभग 30 मिनट लगते हैं!

SQlite में धीमे सम्मिलन के संबंध में मैंने पाया कि अधिकांश मुद्दे लेन-देन को बढ़ाते हैं। लेकिन जब से मैं ContentResolver.applyBatch- विधि का उपयोग करता हूं, तो मैं इसे नियंत्रित नहीं करता हूं, और मैं यह मानूंगा कि ContentResolver मेरे लिए लेनदेन प्रबंधन का ख्याल रखता है।

तो, मेरे प्रश्न के लिए: क्या मैं कुछ गलत कर रहा हूं, या क्या ऐसा कुछ है जो मैं इसे तेज कर सकता हूं?

ऐन्डर्स

संपादित करें: @jcwenger: ओह, मैं देख रहा हूं। अच्छे खर्च!

तो फिर मुझे पहले रॉ_ कॉन्टैक्ट्स टेबल में डालना होगा, और फिर नाम और नंबरों के साथ डेटाटेबल। मैं जो खोता हूं वह रॉ_ड का बैक रेफरेंस है जिसे मैं अप्लाईबेक में उपयोग करता हूं।

तो मुझे डेटा तालिका में विदेशी कुंजी के रूप में उपयोग करने के लिए सभी नए डाले गए रॉ_ कॉन्टैक्ट्स पंक्तियों की आईडी प्राप्त करनी होगी?


ApplyBatch() बजाय ContentResolver.bulkInsert (Uri url, ContentValues[] values) उपयोग करें

ApplyBatch (1) लेनदेन का उपयोग करता है और (2) यह पूरे बैच के लिए एक बार ऑपरेशन के दौरान एक बार लॉक / अनलॉक करने के बजाय ContentProvider को लॉक करता है। इस वजह से, यह उन्हें एक बार (गैर-बैचेड) करने की तुलना में थोड़ा तेज है।

हालांकि, बैच में प्रत्येक ऑपरेशन के बाद एक अलग यूआरआई हो सकता है और इसी तरह, ओवरहेड की एक बड़ी मात्रा है। "ओह, एक नया ऑपरेशन! मुझे आश्चर्य है कि यह किस तालिका में जाता है ... यहां, मैं एक एकल पंक्ति सम्मिलित करूंगा ... ओह, एक नया ऑपरेशन! मुझे आश्चर्य है कि यह किस तालिका में जाता है ..." विज्ञापन infinitium। चूंकि यूआरआई को टेबलों में बदलने के अधिकांश कार्यों में बहुत अधिक स्ट्रिंग तुलना शामिल है, इसलिए यह स्पष्ट रूप से बहुत धीमा है।

इसके विपरीत, बल्क इनवर्टर एक ही तालिका में मानों की एक पूरी ढेर लागू करता है। यह जाता है, "थोक सम्मिलित करें ... तालिका खोजें, ठीक है, सम्मिलित करें! सम्मिलित करें! सम्मिलित करें! सम्मिलित करें! सम्मिलित करें!" काफी तेज।

निस्संदेह, बल्कइंटर कुशलता से लागू करने के लिए आपके ContentResolver की आवश्यकता होगी। अधिकांश करते हैं, जब तक कि आप इसे स्वयं नहीं लिखते हैं, इस स्थिति में यह कोडिंग में थोड़ा सा लगेगा।


मुझे आपके लिए मूल समाधान मिलता है, बैच ऑपरेशन में "उपज अंक" का उपयोग करें।

बैच किए गए संचालन का उपयोग करने का दूसरा पक्ष यह है कि एक बड़ा बैच डेटाबेस को लंबे समय तक अन्य एप्लिकेशन को डेटा तक पहुंचने से रोक सकता है और संभावित रूप से ANRs ("एप्लिकेशन नॉट रिस्पॉन्सिंग") डायलॉग के कारण हो सकता है।

डेटाबेस के ऐसे लॉकअप से बचने के लिए, बैच में " उपज अंक " डालना सुनिश्चित करें। एक उपज बिंदु सामग्री प्रदाता को इंगित करता है कि अगले ऑपरेशन को निष्पादित करने से पहले यह उन परिवर्तनों को कर सकता है जो पहले से किए गए हैं, अन्य अनुरोधों के लिए उपज, एक और लेनदेन खोलें और प्रसंस्करण संचालन जारी रखें।

एक उपज बिंदु स्वचालित रूप से लेनदेन नहीं करेगा, लेकिन केवल तभी जब डेटाबेस पर एक और अनुरोध हो। आम तौर पर एक सिंक एडाप्टर को बैच में प्रत्येक कच्चे संपर्क ऑपरेशन अनुक्रम की शुरुआत में एक उपज बिंदु डालना चाहिए। withYieldAllowed(boolean) देखें।

मुझे आशा है कि यह आपके लिए उपयोगी हो सकता है।


bulkInsert() को ओवरराइड करने के तरीके का एक उदाहरण, मल्टीपल इन्सर्ट को गति देने के लिए, here पाया जा सकता here


बस इस सूत्र के पाठकों की जानकारी के लिए।

मैं भी आवेदन (बैच) का उपयोग करते हुए प्रदर्शन के मुद्दे का सामना कर रहा था। मेरे मामले में तालिका में से एक पर डेटाबेस ट्रिगर लिखा गया था। मैंने तालिका के ट्रिगर और उसके बूम को हटा दिया। अब मेरा ऐप आशीर्वाद तेज गति के साथ पंक्तियों को सम्मिलित करता है।


यहां 30 सेकंड के भीतर समान डेटा राशि सम्मिलित करने का उदाहरण दिया गया है।

 public void testBatchInsertion() throws RemoteException, OperationApplicationException {
    final SimpleDateFormat FORMATTER = new SimpleDateFormat("mm:ss.SSS");
    long startTime = System.currentTimeMillis();
    Log.d("BatchInsertionTest", "Starting batch insertion on: " + new Date(startTime));

    final int MAX_OPERATIONS_FOR_INSERTION = 200;
    ArrayList<ContentProviderOperation> ops = new ArrayList<>();
    for(int i = 0; i < 600; i++){
        generateSampleProviderOperation(ops);
        if(ops.size() >= MAX_OPERATIONS_FOR_INSERTION){
            getContext().getContentResolver().applyBatch(ContactsContract.AUTHORITY,ops);
            ops.clear();
        }
    }
    if(ops.size() > 0)
        getContext().getContentResolver().applyBatch(ContactsContract.AUTHORITY,ops);
    Log.d("BatchInsertionTest", "End of batch insertion, elapsed: " + FORMATTER.format(new Date(System.currentTimeMillis() - startTime)));

}
private void generateSampleProviderOperation(ArrayList<ContentProviderOperation> ops){
    int backReference = ops.size();
    ops.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
            .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null)
            .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
            .withValue(ContactsContract.RawContacts.AGGREGATION_MODE, ContactsContract.RawContacts.AGGREGATION_MODE_DISABLED)
            .build()
    );
    ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                    .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, backReference)
                    .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
                    .withValue(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, "GIVEN_NAME " + (backReference + 1))
                    .withValue(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME, "FAMILY_NAME")
                    .build()
    );
    for(int i = 0; i < 10; i++)
        ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
                        .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, backReference)
                        .withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
                        .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MAIN)
                        .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, Integer.toString((backReference + 1) * 10 + i))
                        .build()
        );
}

लॉग: 02-17 12: 48: 45.496 2073-2090 / com.vayosoft.mlab D / BatchInsertionTest insert बैच सम्मिलन शुरू करने पर: बुध 17 फरवरी 12:48:45 GMT + 02: 00: 02-17 12:49: 16.446 2073-2090 / com.vayosoft.mlab D / BatchInsertionTest ﹕ बैच सम्मिलन का अंत, समाप्त: 00: 30.951







android-contentresolver