थोक में wp_insert_post और add_post_meta का तेज़ तरीका


16

मेरे पास एक सीएसवी फ़ाइल है जिसे मैं सम्मिलित करना चाहता हूं जिसमें ~ 1,500 पंक्तियां और 97 कॉलम शामिल हैं। पूर्ण आयात करने में लगभग 2-3 घंटे लगते हैं और अगर कोई रास्ता है तो मैं इसमें सुधार करना चाहूंगा। वर्तमान में मैं प्रत्येक पंक्ति के लिए 97 पंक्तियों के लिए प्रत्येक पंक्ति के साथ $ post_id = wp_insert_post और उसके बाद एक add_post_meta कर रहा हूं। यह बहुत अक्षम है ...

क्या इस तरह से इसके बारे में जाने के लिए एक बेहतर तरीका है कि पोस्ट_डिट के बाद और इसके पोस्ट_मेटा मूल्यों के बीच संबंध बनाए रख सकते हैं?

अभी मैं wamp के साथ अपने स्थानीय मशीन पर यह कोशिश कर रहा हूँ, लेकिन क्या यह VPS पर चल रहा है


नीचे WP युक्तियों के अलावा, MySQL में InnoDB का उपयोग करने और इस उत्तर के अनुसार बैचों में लेनदेन करने पर भी ध्यान दें ।
वेबवार्ता

जवाबों:


21

कस्टम CSV आयात के साथ कुछ समय पहले मुझे भी ऐसी ही समस्याएं थीं, लेकिन मैंने बल्क इंसर्ट के लिए कुछ कस्टम SQL का उपयोग करके समाप्त किया। लेकिन मैंने यह उत्तर तब तक नहीं देखा था:

बल्क ऑपरेशन के लिए पोस्ट इंसर्ट और डिलीट को ऑप्टिमाइज़ करें?

wp_defer_term_counting()शब्द गणना को सक्षम या अक्षम करने के लिए उपयोग करने के लिए।

यदि आप वर्डप्रेस आयातक प्लगइन के लिए स्रोत की जांच करते हैं , तो आप थोक आयात से ठीक पहले इन कार्यों को देखेंगे:

wp_defer_term_counting( true );
wp_defer_comment_counting( true );

और फिर थोक डालने के बाद:

wp_defer_term_counting( false );
wp_defer_comment_counting( false );

तो यह बाहर की कोशिश करने के लिए कुछ हो सकता है ;;;

प्रकाशन के बजाय ड्राफ्ट के रूप में पोस्ट आयात करना , चीजों को गति भी देगा, क्योंकि हर एक के लिए एक अद्वितीय स्लग खोजने की धीमी प्रक्रिया को छोड़ दिया जाता है। उदाहरण के लिए, उन्हें बाद में छोटे चरणों में प्रकाशित किया जा सकता है, लेकिन ध्यान दें कि इस तरह के दृष्टिकोण को किसी तरह आयातित पोस्ट को चिह्नित करने की आवश्यकता होगी, इसलिए हम बाद में किसी भी ड्राफ्ट को प्रकाशित नहीं करते हैं! इसके लिए सावधानीपूर्वक नियोजन की आवश्यकता होगी और सबसे अधिक संभावना है कि कुछ कस्टम कोडिंग।

यदि कोई समान पोस्ट शीर्षक (समान post_name) के बहुत सारे आयात किए जाने हैं, तो wp_unique_post_slug()उपलब्ध स्लग खोजने के लिए लूप क्वेरी पुनरावृत्ति के कारण धीमा हो सकता है। यह संभवतः बड़ी संख्या में db क्वेरी उत्पन्न कर सकता है।

वर्डप्रेस 5.1 के बाद pre_wp_unique_post_slugसे स्लग के लिए लूप पुनरावृत्ति से बचने के लिए फ़िल्टर उपलब्ध है। कोर टिकट देखें # 21112 । यहाँ एक उदाहरण है:

add_filter( 'pre_wp_unique_post_slug', 
    function( $override_slug, $slug, $post_id, $post_status, $post_type, $post_parent ) {
        // Set a unique slug value to shortcircuit the slug iteration loop.
        // $override_slug = ...

        return $override_slug;
    }, 10, 6
);

एक कोशिश करता जैसे हैं $override_slug = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix"के साथ $suffixके रूप में $post_id, तो हम ध्यान दें होता है कि $post_idहमेशा होता है 0की उम्मीद के रूप में नए पदों के लिए,। हालांकि PHP में अद्वितीय संख्याओं को उत्पन्न करने के लिए विभिन्न तरीके हैं, जैसे uniqid( '', true )। लेकिन इस फ़िल्टर का उपयोग यह सुनिश्चित करने के लिए करें कि आपके पास अद्वितीय स्लग हैं। हम उदाहरण के post_nameलिए सुनिश्चित करने के लिए बाद में एक समूह गणना क्वेरी चला सकते हैं ।

एक अन्य विकल्प यह होगा कि टाइमआउट से बचने के लिए WP-CLI का उपयोग किया जाए । उदाहरण के लिए, .csv फ़ाइल का उपयोग करके 20,000 पोस्ट या पेज बनाने के लिए पोस्ट किए गए मेरे उत्तर देखें ?

फिर हम import.phpWP-CLI कमांड के साथ हमारे कस्टम PHP आयात स्क्रिप्ट को चला सकते हैं :

wp eval-file import.php

इसके अलावा बड़ी संख्या में पदानुक्रमित पोस्ट प्रकारों को आयात करने से बचें, क्योंकि वर्तमान wp-admin UI इसे अच्छी तरह से नहीं संभालता है। उदाहरण के लिए देखें कस्टम पोस्ट प्रकार - पदों की सूची - मौत की सफेद स्क्रीन

यहाँ @ आदर्श से महान टिप है:

थोक आवेषण से पहले , autocommitमोड को स्पष्ट रूप से अक्षम करें :

$wpdb->query( 'SET autocommit = 0;' );

थोक आवेषण के बाद, चलाएँ:

$wpdb->query( 'COMMIT;' );

मुझे भी लगता है कि कुछ हाउसकीपिंग करना अच्छा होगा, जैसे:

$wpdb->query( 'SET autocommit = 1;' );

मैंने MyISAM पर इसका परीक्षण नहीं किया है लेकिन यह InnoDB पर काम करना चाहिए ।

जैसा कि @kovshenin ने बताया है कि यह टिप MyISAM के लिए काम नहीं करेगा ।


6
इसके अलावा, आप पहले ऑटोकेमिट को बंद करने के लिए क्वेरी फ़ंक्शन का भी उपयोग कर सकते हैं, और फिर सम्मिलन किए जाने के बाद मैन्युअल रूप से प्रतिबद्ध कर सकते हैं। यह थोक आवेषण करते समय DB स्तर पर परिचालन को बहुत तेज करता है। बस SET autocommit=0;आवेषण से पहले भेजें , उसके COMMIT;बाद बाद में।
ओटो

दिलचस्प है, इसके लिए धन्यवाद! घर पहुंचने पर मुझे इसका परीक्षण करना होगा।
कोरी रोवेल

@ अच्छा, महान टिप के लिए धन्यवाद। तो हम $wpdb->query('SET autocommit = 0;');आवेषण से पहले कर सकते हैं लेकिन क्या हम $wpdb->query('START TRANSACTION;');उस मामले में छोड़ सकते हैं ? मैं इसके बारे में और अधिक जानने के लिए MySQL मैनुअल की जाँच करूँगा ;-) चीयर्स।
बिरगिरे

1
अच्छा बिंदु मार्क। यदि ये केवल आवेषण हैं और अपडेट नहीं हैं, तो wp_suspend_cache_addition( true )ऑब्जेक्ट कैश में सामान नहीं रखने में मदद करनी चाहिए। इसके अलावा @birgire ने उल्लेख किया कि उन्होंने MyISAM के साथ इसका परीक्षण नहीं किया है - परेशान मत करो, भंडारण इंजन लेनदेन का समर्थन नहीं करता है इसलिए ऑटोोकॉम सेट करना या लेनदेन शुरू करना शून्य प्रभाव होगा।
कोवशेनिन

1
महान टिप @ ओटो। मेरी क्वेरी पहले 38 सेकंड लेती थी, अब इसमें 1sec लगता है।
अन्नपूर्णा

5

आपको अपनी आईडी प्राप्त करने के लिए पोस्ट डालने की आवश्यकता होगी लेकिन $wpdb->postmetaतालिका संरचना में बहुत सरल है। आप शायद MySQL डॉक्स से इस तरह एक सीधे INSERT INTOबयान का उपयोग कर सकते हैं :INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);

आपके मामले में...

$ID = 1; // from your wp_insert_post
$values = '($ID,2,3),($ID,5,6),($ID,8,9)'; // build from your 97 columns; I'd use a loop of some kind
$wpdb->query("INSERT INTO {$wpdb->postmeta} (post_id,meta_key,meta_value) VALUES {$values}");

यह किसी भी एन्कोडिंग, क्रमांकन, भागने, त्रुटि की जाँच, दोहराव, या किसी अन्य चीज़ से नहीं होगा, लेकिन मुझे उम्मीद है कि यह तेज़ होगा (हालांकि मैंने कोशिश नहीं की है)।

मैं पूरी तरह से परीक्षण किए बिना एक उत्पादन साइट पर ऐसा नहीं करूंगा, और अगर मुझे केवल एक या दो बार ऐसा करना पड़ा, तो मैं मुख्य कार्यों का उपयोग करूंगा और चीजों को आयात करते समय एक लंबा दोपहर का भोजन करूंगा।


लगता है कि मैं एक लंबा लंच लूंगा, बल्कि अपने टेबल में कच्चा डेटा नहीं डालूंगा और इसका कोई मतलब नहीं है कि वर्डप्रेस पहले से क्या करेगा।
कोरी रोवेल

1
इस तरह mysql इंजेक्शन होता है, इसलिए कृपया इसका उपयोग न करें।
OneOfOne

सब कुछ हार्ड-कोडेड है, @OneOfOne। इंजेक्शन नहीं होता है - परिभाषा के अनुसार नहीं हो सकता है - उपयोगकर्ता द्वारा प्रदत्त इनपुट के बिना। वह "इंजेक्शन" की प्रकृति है। ओपी एक .csv फ़ाइल से डेटा आयात कर रहा है जो उसके नियंत्रण में कोड का उपयोग करके उसके नियंत्रण में है। किसी भी चीज को इंजेक्ट करने के लिए किसी थर्ड पार्टी के पास अपारदर्शिता नहीं होती है। कृपया संदर्भ पर ध्यान दें।
s_ha_dum

मेरे से +1, मुझे 20 सीमा शुल्क फ़ील्ड मान जोड़ने की आवश्यकता है और यह "add_post_meta" की तुलना में बहुत तेज़ था
ज़ोरॉक्स

1
आप आयात करने से पहले CS से पूरी तरह से CSV फ़ाइल की जांच करने की उम्मीद नहीं कर सकते हैं, और इसलिए आपको इसे उपयोगकर्ता इनपुट के रूप में और कम से कम ->prepare()अपने SQL बयानों के साथ व्यवहार करना चाहिए । आपके परिदृश्य में, यदि CSV में ID कॉलम कुछ ऐसा होता है तो क्या होगा 1, 'foo', 'bar'); DROP TABLE wp_users; --? शायद कुछ बुरा है।
कोवशेनिन

5

मुझे इसे जोड़ना था:

    remove_action('do_pings', 'do_all_pings', 10, 1);

ध्यान रखें कि यह छोड़ देगा do_all_pings, जो पिंगबैक, एनक्लोजर, ट्रैकबैक और अन्य पिंग्स (लिंक: https://developer.wordpress.org/reference/functions/do_all_pings/ ) को संसाधित करता है । कोड को देखने से मेरी समझ यह है कि आपके द्वारा इस remove_actionलाइन को हटाने के बाद भी लंबित पिंगबैक / ट्रैकबैक / एनक्लोजर पर कार्रवाई की जाएगी , लेकिन मुझे पूरा यकीन नहीं है।

अद्यतन: मैंने भी जोड़ा

    define( 'WP_IMPORTING', true );

उससे परे जो मैं उपयोग कर रहा हूं:

    ini_set("memory_limit",-1);
    set_time_limit(0);
    ignore_user_abort(true);

    wp_defer_term_counting( true );
    wp_defer_comment_counting( true );
    $wpdb->query( 'SET autocommit = 0;' );

    /* Inserting 100,000 posts at a time
       including assigning a taxonomy term and adding meta keys
       (i.e. a `foreach` loop with each loop containing:
       `wp_insert_post`, `wp_set_object_terms`, `add_post_meta`.)
    */

    $wpdb->query( 'COMMIT;' );
    wp_defer_term_counting( false );
    wp_defer_comment_counting( false );

1

के बारे में महत्वपूर्ण नोट 'SET autocommit = 0;'

सेट करने के बाद autocommit = 0यदि स्क्रिप्ट का निष्पादन बंद हो जाता है (किसी कारण, जैसे exit, घातक त्रुटि या आदि ...), तो आपके परिवर्तन DB के साथ हो जाएंगे!

$wpdb->query( 'SET autocommit = 0;' );

update_option("something", "value");     

exit; //lets say, here happens error or anything...

$wpdb->query( 'COMMIT;' );

इस मामले update_optionमें DB में नहीं बचाया जाएगा!

इसलिए, सबसे अच्छी सलाह यह है कि COMMITआप shutdownएक पूर्वानुमेय के रूप में फ़ंक्शन में पंजीकृत हों (यदि कोई अप्रत्याशित निकास होता है)।

register_shutdown_function( function(){
    $GLOBALS['wpdb']->query( 'COMMIT;' );
} );
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.