पोस्टमैटा के साथ पोस्ट प्राप्त करने का सबसे कुशल तरीका


36

मुझे उनके मेटाडेटा के साथ पदों का एक गुच्छा प्राप्त करने की आवश्यकता है। बेशक आप एक मानक पोस्ट क्वेरी के साथ मेटाडेटा प्राप्त नहीं कर सकते हैं, इसलिए आपको आमतौर पर get_post_custom()प्रत्येक पोस्ट के लिए करना होगा ।

मैं इस तरह से एक कस्टम क्वेरी के साथ कोशिश कर रहा हूँ:

$results = $wpdb->get_results("
    SELECT  p.ID,
        p.post_title,
        pm1.meta_value AS first_field,
        pm2.meta_value AS second_field,
        pm3.meta_value AS third_field
    FROM    $wpdb->posts p LEFT JOIN $wpdb->postmeta pm1 ON (
            pm1.post_id = p.ID  AND
            pm1.meta_key    = 'first_field_key'
        ) LEFT JOIN $wpdb->postmeta pm2 ON (
            pm2.post_id = p.ID  AND
            pm2.meta_key    = 'second_field_key'
        ) LEFT JOIN $wpdb->postmeta pm3 ON (
            pm3.post_id = p.ID  AND
            pm3.meta_key    = 'third_field_key'
        )
    WHERE   post_status = 'publish'
");

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

तो, प्रश्न 1: क्या बहु-मूल्य वाले मेटा फ़ील्ड में शामिल होने के लिए कोई जोड़, उप-क्वेरी या कुछ भी है?

लेकिन सवाल 2: क्या यह इसके लायक है? postmeta2-क्वेरी दृष्टिकोण के बेहतर होने से पहले मैं कितनी टेबल जोड़ता हूं? मैं एक क्वेरी में सभी पोस्ट डेटा को पकड़ सकता था, फिर दूसरे में सभी प्रासंगिक पोस्टमेट को पकड़ सकता था, और PHP में एक परिणाम में पोस्ट डेटा के साथ मेटा को संयोजित कर सकता था। क्या यह एक एकल-अधिक-जटिल एसक्यूएल क्वेरी की तुलना में तेज हो सकता है, अगर यह भी संभव है?

मैं हमेशा सोचता हूं, "डेटाबेस को जितना संभव हो उतना काम दें।" इस पर यकीन नहीं!


मुझे यकीन नहीं है कि अगर आप भी जॉइन करना चाहते हैं। get_posts () और get_post_meta () का संयोजन आपको समान डेटा वापस देता है। वास्तव में, यह आपके द्वारा बाद में उपयोग नहीं किए जाने वाले डेटा को पुनः प्राप्त करने के बाद से जॉइन का उपयोग करके कम कुशल है।
२३

2
वैसे भी मेटा डेटा स्वचालित रूप से कैश नहीं किया जाता है?
मैन्नी फ्लेममंड

@rxn, अगर मेरे पास कई सौ पोस्ट वापस आ रहे हैं (वे एक कस्टम पोस्ट प्रकार हैं), निश्चित रूप से यह काफी भारी डीबी लोड है get_posts(), तो get_post_meta()उनमें से हर एक के लिए? @MannyFleurmond, WP के बिल्ट-इन कैशिंग के बारे में कठिन जानकारी प्राप्त करना कठिन है, लेकिन AFAIK यह आपके अनुरोध के अनुसार सामान को कैश कर देगा। इस डेटा को हड़पने के लिए सर्वर को कॉल एक AJAX कॉल है, और मुझे नहीं लगता कि इससे पहले कुछ और सामान कब्जाने वाला होगा।
स्टीव टेलर

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

जवाबों:


58

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

इसलिए, आपको इसके लिए अपनी क्वेरी नहीं लिखनी चाहिए।

सामान्य प्रश्नों के लिए मेटा कैशिंग कैसे काम करता है:

यदि update_post_meta_cacheपैरामीटर को WP_Queryगलत पर सेट नहीं किया गया है, तो DB से पदों को पुनर्प्राप्त करने के बाद, फिर update_post_caches()फ़ंक्शन को कॉल किया जाएगा, जो बदले में कॉल करता है update_postmeta_cache()

update_postmeta_cache()समारोह के लिए एक आवरण है update_meta_cache(), और यह अनिवार्य रूप से एक साधारण कॉल SELECTसभी आईडी की पोस्ट को पुनः प्राप्त की है। यह क्वेरी में सभी पदों के लिए, और उस डेटा को ऑब्जेक्ट कैश (उपयोग wp_cache_add()) में सहेजने के लिए सभी पोस्टमेट को प्राप्त करेगा ।

जब आप कुछ ऐसा करते हैं get_post_custom(), तो यह पहले उस ऑब्जेक्ट कैश की जाँच कर रहा है। इसलिए इस बिंदु पर पोस्ट मेटा प्राप्त करने के लिए यह अतिरिक्त पूछताछ नहीं कर रहा है। यदि आपने पोस्ट को एक में डाल दिया है WP_Query, तो मेटा पहले से ही मेमोरी में है और इसे वहां से सीधे प्राप्त होता है।

यहां लाभ एक जटिल क्वेरी बनाने से कई गुना अधिक हैं, लेकिन सबसे बड़ा फायदा ऑब्जेक्ट कैश का उपयोग करने से आता है। यदि आप लगातार मेमोरी कैशिंग समाधान जैसे कि XCache या मेमकाटेड या APC या ऐसा कुछ का उपयोग करते हैं, और एक प्लगइन है जो आपके ऑब्जेक्ट कैश को उसमें बाँध सकता है (उदाहरण के लिए W3 Total Cache), तो आपका पूरा ऑब्जेक्ट कैश तेज मेमोरी में संग्रहीत होता है पहले से। किस स्थिति में, आपके डेटा को पुनः प्राप्त करने के लिए शून्य प्रश्न आवश्यक हैं; यह पहले से ही स्मृति में है। लगातार ऑब्जेक्ट कैशिंग कई मामलों में भयानक है।

दूसरे शब्दों में, आपकी क्वेरी संभवतः एक उचित क्वेरी और एक सरल निरंतर मेमोरी समाधान का उपयोग करने की तुलना में धीमी और लोड होती है। सामान्य का उपयोग करें WP_Query। अपने आप को कुछ प्रयास बचाओ।

अतिरिक्त: update_meta_cache() स्मार्ट है, BTW। यह उन पोस्टों के लिए मेटा जानकारी पुनर्प्राप्त नहीं करेगा जिनके पास पहले से ही उनकी मेटा जानकारी कैश है। यह दो बार एक ही मेटा नहीं मिलता है, मूल रूप से। सुपर कुशल।

अतिरिक्त अतिरिक्त: "डेटाबेस को जितना संभव हो उतना काम दें।" ... नहीं, यह वेब है। अलग-अलग नियम लागू होते हैं। सामान्य तौर पर, आप हमेशा डेटाबेस के लिए जितना संभव हो उतना कम काम देना चाहते हैं , अगर यह संभव है। डेटाबेस धीमा या खराब तरीके से कॉन्फ़िगर किया गया है (यदि आपने इसे विशेष रूप से कॉन्फ़िगर नहीं किया है, तो आप अच्छे पैसे पर शर्त लगा सकते हैं कि यह सच है)। अक्सर वे कई साइटों के बीच साझा किए जाते हैं, और कुछ हद तक अतिभारित होते हैं। आमतौर पर आपके पास डेटाबेस से अधिक वेब सर्वर होते हैं। सामान्य तौर पर, आप केवल उस डेटा को प्राप्त करना चाहते हैं जिसे आप डीबी से बाहर जितनी जल्दी और बस संभव हो सके, फिर वेब-सर्वर-साइड कोड का उपयोग करके उसमें से छंटनी करें। एक सामान्य सिद्धांत के रूप में, निश्चित रूप से, विभिन्न मामले सभी अलग-अलग हैं।


30

मैं एक पिवट क्वेरी की सलाह दूंगा। अपने उदाहरण का उपयोग करना:

SELECT  p.ID,   
        p.post_title, 
        MAX(CASE WHEN wp_postmeta.meta_key = 'first_field' then wp_postmeta.meta_value ELSE NULL END) as first_field,
        MAX(CASE WHEN wp_postmeta.meta_key = 'second_field' then wp_postmeta.meta_value ELSE NULL END) as second_field,
        MAX(CASE WHEN wp_postmeta.meta_key = 'third_field' then wp_postmeta.meta_value ELSE NULL END) as third_field,

 FROM    wp_posts p LEFT JOIN wp_postmeta pm1 ON ( pm1.post_id = p.ID)                      
GROUP BY
   wp_posts.ID,wp_posts.post_title

यह उत्तर सही होना चाहिए।
ल्यूक

यदि आप डेटाबेस क्वेरी की तलाश कर रहे हैं तो यह सही उत्तर है
एलेक्स पोपोव

इस क्वेरी ने मेरा समय कम कर दिया जब मैं WP_Query को ~ 25 सेकंड से ~ 3 सेकंड तक उपयोग कर रहा था। मेरी आवश्यकता केवल एक बार फायर करने की थी इसलिए किसी कैशिंग की आवश्यकता नहीं थी।
कुश

11

मैं एक ऐसे मामले में आया हूँ जहाँ मैं यह भी चाहता हूँ कि उनकी संबद्ध मेटा जानकारी के साथ बहुत सी पोस्ट को जल्दी से पुनः प्राप्त किया जाए। मुझे O (2000) पोस्ट पुनः प्राप्त करने की आवश्यकता है।

मैंने इसे ओटो के सुझाव का उपयोग करके देखा - सभी पोस्टों के लिए WP_Query :: क्वेरी चला रहा है, और फिर प्रत्येक पोस्ट के लिए get_post_custom के माध्यम से चल रहा है। इसे पूरा होने में औसतन लगभग 3 सेकंड का समय लगा

फिर मैंने एथन की धुरी की क्वेरी की कोशिश की (हालाँकि मुझे यह पसंद नहीं था कि मैं प्रत्येक मेटा_की दिलचस्पी लेना चाहता था)। मुझे अभी भी सभी पुनर्प्राप्त पदों के माध्यम से लूप करना था ताकि मेटा_वल्यू को अनसुना किया जा सके। इसे पूरा होने में औसतन लगभग 1.3 सेकंड का समय लगा

मैंने तब GROUP_CONCAT फ़ंक्शन का उपयोग करने की कोशिश की, और सबसे अच्छा परिणाम मिला। यहाँ कोड है:

global $wpdb;
$wpdb->query('SET SESSION group_concat_max_len = 10000'); // necessary to get more than 1024 characters in the GROUP_CONCAT columns below
$query = "
    SELECT p.*, 
    GROUP_CONCAT(pm.meta_key ORDER BY pm.meta_key DESC SEPARATOR '||') as meta_keys, 
    GROUP_CONCAT(pm.meta_value ORDER BY pm.meta_key DESC SEPARATOR '||') as meta_values 
    FROM $wpdb->posts p 
    LEFT JOIN $wpdb->postmeta pm on pm.post_id = p.ID 
    WHERE p.post_type = 'product' and p.post_status = 'publish' 
    GROUP BY p.ID
";

$products = $wpdb->get_results($query);

// massages the products to have a member ->meta with the unserialized values as expected
function massage($a){
    $a->meta = array_combine(explode('||',$a->meta_keys),array_map('maybe_unserialize',explode('||',$a->meta_values)));
    unset($a->meta_keys);
    unset($a->meta_values);
    return $a;
}

$products = array_map('massage',$products);

इसने औसतन 0.7 सेकंड का समय लिया । यह WP get_post_custom () समाधान के लगभग एक चौथाई समय और धुरी क्वेरी समाधान के लगभग आधे हिस्से के बारे में है।

शायद यह किसी के लिए ब्याज की होगी।


मुझे इस बात में दिलचस्पी होगी कि आपको लगातार ऑब्जेक्ट कैश समाधान के साथ क्या परिणाम मिलते हैं। ऑब्जेक्ट कैश कभी-कभी आपके डेटाबेस और कॉन्फ़िगरेशन के आधार पर आधार मामले के लिए धीमा हो जाएगा, लेकिन अधिकांश मेजबानों के साथ वास्तविक दुनिया के परिणाम व्यापक रूप से भिन्न परिणाम देंगे। मेमोरी आधारित कैशिंग हास्यास्पद रूप से तेज है।
ओटो

अरे @ ओटो। डेटा प्राप्त करने के लिए मैं किस पद्धति का उपयोग करता हूं, मैं निश्चित रूप से परिणाम को कैश करना चाहता हूं। मैंने इसे करने के लिए क्षणिक एपीआई का उपयोग करने की कोशिश की है, लेकिन मैं स्मृति समस्याओं को मार रहा हूं। ~ 8M और set_transient () विफल (स्मृति समाप्त) पर मेरी 2000 ऑब्जेक्ट घड़ियों के लिए क्रमबद्ध स्ट्रिंग। इसके अलावा, max_allowed_packet MySQL सेटिंग को बदलना होगा। मैं इसे फ़ाइल करने के लिए कैशिंग में देखूंगा, लेकिन मुझे यकीन नहीं है कि वहां प्रदर्शन अभी तक है। क्या स्मृति को कैश करने का एक तरीका है जो अनुरोधों पर निर्भर रहता है?
ट्रेवर मिल्स

हां, यदि आपके पास लगातार मेमोरी कैश (XCache, मेमकाटेड, APC, आदि) है, और ऑब्जेक्ट कैशिंग प्लगइन का उपयोग करें (W3 Total Cache कई प्रकार के मेमोरी कैश का समर्थन करता है), तो यह मेमोरी में सभी ऑब्जेक्ट कैश को स्टोर करता है, जिससे आपको एक बहुत ज्यादा सब कुछ के कई गुना गति।
ओटो

मैं एक रीढ़ / अंडरस्कोर जेएस फ़िल्टरिंग योजना में उपयोग करने के लिए 6000 आइटम वापस कर रहा हूं। इसने 6s कस्टम क्वेरी ली जिसे मैं WP_Query के रूप में भी नहीं चला सकता था क्योंकि यह समय समाप्त हो गया था, और इसे 2s क्वेरी बना दिया। हालाँकि array_map इसे काफी धीमा कर देता है ...
Jake

क्या WP_Query के भीतर सभी मेटा डेटा को वापस करने के लिए उच्च प्रदर्शन का समर्थन करने के लिए कोई समर्थन है?
atwellpub

2

मैंने खुद को इस स्थिति में पाया कि मुझे अंततः एक सीएसवी दस्तावेज़ बनाने के लिए इस कार्य को करने की आवश्यकता थी, मैंने ऐसा करने के लिए सीधे mysql के साथ काम करना समाप्त कर दिया। मेरा कोड woocommerce मूल्य निर्धारण की जानकारी को पुनः प्राप्त करने के लिए पोस्ट और मेटा टेबल से जुड़ता है, पहले से पोस्ट किए गए समाधान की आवश्यकता है कि मैं ठीक से काम करने के लिए sql में टेबल उपनाम का उपयोग करता हूं।

SELECT p.ID, p.post_title, 
    MAX(CASE WHEN pm1.meta_key = '_price' then pm1.meta_value ELSE NULL END) as price,
    MAX(CASE WHEN pm1.meta_key = '_regular_price' then pm1.meta_value ELSE NULL END) as regular_price,
    MAX(CASE WHEN pm1.meta_key = '_sale_price' then pm1.meta_value ELSE NULL END) as sale_price,
    MAX(CASE WHEN pm1.meta_key = '_sku' then pm1.meta_value ELSE NULL END) as sku
    FROM wp_posts p LEFT JOIN wp_postmeta pm1 ON ( pm1.post_id = p.ID)                 
    WHERE p.post_type in('product', 'product_variation') AND p.post_status = 'publish'
    GROUP BY p.ID, p.post_title

हालांकि चेतावनी दी जाती है, woocommerce ने मेरी मेटा तालिका में 300K + पंक्तियाँ बनाईं, इसलिए यह बहुत बड़ी थी, और इसलिए बहुत धीमी थी।


1

कोई SQL संस्करण:

सभी पोस्ट और उनके सभी मेटा मान (मेटा) बिना किसी SQL के प्राप्त करें:

मान लीजिए कि आपके पास कुछ ऐसे आईडी के रूप में संग्रहीत पोस्ट आईडी की सूची है, जैसे कुछ

$post_ids_list = [584, 21, 1, 4, ...];

अब 1 क्वेरी में सभी पोस्ट और सभी मेटा प्राप्त करना कम से कम एसक्यूएल का उपयोग किए बिना संभव नहीं है, इसलिए हमें 2 प्रश्न करना चाहिए (अभी भी सिर्फ 2):

1. सभी पोस्ट प्राप्त करें ( WP_Query का उपयोग करके )

$request = new WP Query([
  'post__in' => $post_ids_list,
  'ignore_sticky_posts' => true, //if you want to ignore the "stickiness"
]);

( wp_reset_postdata();यदि आप बाद में "लूप" कर रहे हैं तो कॉल करना न भूलें ;))

2. मेटा कैश अपडेट करें

//don't be confused here: "post" means content type (post X user X ...), NOT post type ;)
update_meta_cache('post', $post_ids_list);

मेटा डेटा प्राप्त करने के लिए बस उस मानक का उपयोग करें get_post_meta(), जैसा @Otto ने बताया:
पहले कैश में दिखता है :)

नोट: यदि आपको वास्तव में पदों से अन्य डेटा (जैसे शीर्षक, सामग्री, ...) की आवश्यकता नहीं है, तो आप सिर्फ 2. :-)


0

समाधान प्रपत्र ट्रेवर का उपयोग करके और इसे नेस्टेड SQL के साथ काम करने के लिए संशोधित करना। यह परीक्षण नहीं किया गया है।

global $wpdb;
$query = "
    SELECT p.*, (select pm.* From $wpdb->postmeta AS pm WHERE pm.post_id = p.ID)
    FROM $wpdb->posts p 
    WHERE p.post_type = 'product' and p.post_status = 'publish' 
";
$products = $wpdb->get_results($query);

-1

मैं कई मूल्य मेटा फ़ील्ड समस्या में भी भाग गया। समस्या वर्डप्रेस के साथ ही है। Wp- शामिल / meta.php में देखें। इस पंक्ति को देखें:

$where[$k] = ' (' . $where[$k] . $wpdb->prepare( "CAST($alias.meta_value AS {$meta_type}) {$meta_compare} {$meta_compare_string})", $meta_value );

समस्या CAST कथन के साथ है। मेटा मानों की क्वेरी में, $ meta_type वैरिएबल CHAR पर सेट है। मुझे इस बारे में जानकारी नहीं है कि CHAR के मान को कैसे बढ़ाया जाना क्रमबद्ध स्ट्रिंग को प्रभावित करता है, लेकिन इसे ठीक करने के लिए, आप कास्ट को निकाल सकते हैं ताकि SQL इस तरह दिखे:

$where[$k] = ' (' . $where[$k] . $wpdb->prepare( "$alias.meta_value {$meta_compare} {$meta_compare_string})", $meta_value );

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

जिस तरह से मैंने तय किया है कि मैं चाहता हूं कि मेटा क्वेरी के लिए वर्डप्रेस द्वारा बनाई गई एसक्यूएल की नकल करें और फिर मैं जो कुछ देख रहा हूं, उसके लिए अतिरिक्त PHP और स्टेटमेंट से निपटने के लिए कुछ PHP लिखो और $ wpdb-> get_results ($ sql) का उपयोग करें ) अंतिम आउटपुट के लिए। हैकी, लेकिन यह काम करता है।


मैंने इसे आज़माया नहीं है, लेकिन get_meta_sqlइस लाइन का अनुसरण करने वाले फ़िल्टर का लाभ उठाना निश्चित रूप से कोर कोड को हैक करने के लिए बेहतर होगा।
स्टीव टेलर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.