तेजी से बचत एकल क्षेत्र मूल्य


19

मुझे अपनी साइट पर लगभग 70k नोड्स निर्दिष्ट प्रकार के मिले हैं। मुझे उन पर एक अपडेट चलाने की आवश्यकता है। कुछ संचालन और एक फ़ील्ड को वांछित मान पर सेट करना। node_saveवास्तव में धीमा है और यह दुर्घटनाओं का कारण बनता है (बहुत लंबा कॉलस्टैक मेबी)। क्या इस एक विशेष क्षेत्र पर जानकारी लिखने का तेज़ तरीका है?

field_attach_updateएक पोस्ट में उल्लेख किया गया था , लेकिन यह बहुत तेज़ नहीं है।

EDIT: इस नोड प्रकार पर निर्मित काफी जटिल दृश्य है, लेकिन इस क्षेत्र पर काम नहीं कर रहा हूं जिसे मैं अपडेट करना चाहता हूं।

जवाबों:


30

मैं जरूर जाऊंगा field_attach_update

विचार सरल है। बस नोड को लोड करें और इसे field_attach_update का उपयोग करके सहेजें।

उदाहरण के लिए:

$node = node_load($nid);
$node->field_name[LANGUAGE_NONE][0]['value'] = 'New value';
field_attach_presave('node', $node);
field_attach_update('node', $node);
  // Clear the static loading cache.
entity_get_controller('node')->resetCache(array($node->nid));

यह किसी भी टाइमस्टैम्प या किसी अन्य हुक को नहीं बदलेगा जो कि नोड_सेव आमतौर पर आह्वान करता है। लोड हो रहा है नोड भी कुछ हुक आह्वान करेगा तो शायद यह इतना कुशल नहीं है।

यदि आपके पास निड है और यदि नोड संरचना मृत सरल है, तो आप इसे इस तरह भी कर सकते हैं:

 $node = new stdClass();
 $node->nid = $nid; // Enter the nid taken. Make sure it exists. 
 $node->type = 'article';
 $node->field_name[LANGUAGE_NONE][0]['value'] = 'New value';
 field_attach_presave('node', $node);
 field_attach_update('node', $node);
  // Clear the static loading cache.
 entity_get_controller('node')->resetCache(array($node->nid));

वैसे भी, यदि आप फ़ील्ड के अलावा कुछ भी अपडेट करने का प्रयास कर रहे हैं, तो यह काम नहीं करेगा (टिप्पणी स्थिति, प्रकाशित स्थिति, आदि)। इसके अलावा, यदि आप नोड_सेवे का उपयोग कर रहे हैं, तो विशेष नोड के लिए कैश को विभिन्न तरीकों के लिए स्वचालित रूप से साफ़ कर दिया जाएगा, जिसे हमें 'एंट्री_गेट_कंट्रोलर' से साफ़ करना होगा।

अद्यतन: ऐसा प्रतीत होता है कि आपको field_attach_presave()अन्य मॉड्यूल को फ़ील्ड इनपुट को ठीक से संसाधित करने देने के लिए भी कॉल करना चाहिए । फ़ाइल मॉड्यूल, उदाहरण के लिए, इस हुक का उपयोग करके फ़ाइल की स्थिति को स्थायी करने के लिए इसका उपयोग करता है। मैंने ऊपर अपने 2 उदाहरण अपडेट किए हैं।


मेरे पास nid है, लेकिन नोड के लिए संरचना इतनी सरल नहीं है, लेकिन मैं जिस क्षेत्र को अपडेट करना चाहता हूं वह मृत सरल है। मौजूदा नोड के लिए केवल एक फ़ील्ड सेट करने से मैं क्या उम्मीद कर सकता हूं (nid द्वारा पहचाना गया लेकिन लोड नहीं किया गया) और फिर कॉल करना field_attach_update?
एलार

4
चूंकि यह इकाई क्वेरी का उपयोग करके पता लगाता है, इसलिए यह चीजों को धीमा कर रहा था। से स्विच तो node_saveकरने के लिए field_attach_updateऔर से EntityFieldQueryकरने के लिए db_query_rangeकाफी पुरस्कृत किया गया था। 3h अपडेट से 40 मिनट तक।
एलोर

2

यदि आप मानक घटनाओं और कार्यों को किए बिना फ़ील्ड डेटा को सहेजना नहीं चाहते हैं तो आप drupal_write_record का उपयोग कर सकते हैं ।

यहाँ 1 की आईडी के साथ एक प्रकार के लेख के नोड के लिए शरीर के क्षेत्र में हैलो वर्ल्ड सम्मिलित करने के लिए एक उदाहरण है।

$values = array(
  'entity_type' => 'node',
  'bundle' => 'article',
  'entity_id' => 1,
  'revision_id' => 1,
  'language' => 'und',
  'delta' => 0,
  'body_value' => 'HELLO WORLD',
  'body_summary' => '',
  'body_format' => 'filtered_html',
);
drupal_write_record('field_data_body', $values);
drupal_write_record('field_revision_body', $values);

यदि आपकी साइट बहुभाषी है, तो आप 'und' के बजाय 'en' या अपनी सामग्री की भाषा का उपयोग करना चाहेंगे।

यदि आप संशोधन कर रहे हैं, तो आपको सही संशोधन आईडी सम्मिलित करने के लिए सावधान रहना होगा, अन्यथा आप केवल यूनिट_ड के समान मान सम्मिलित कर सकते हैं।

ध्यान दें कि यह डेटा कैसे दो तालिकाओं में डाला जाता है field_data_ * और field_revision_ *। आपको यह सुनिश्चित करने के लिए दोनों को सम्मिलित करना चाहिए कि साइट वांछित के रूप में काम करती है।

इसे चलाने के बाद आपको अपने कैशिंग सेटअप के आधार पर फ़ील्ड को दिखाने के लिए कैश साफ़ करने की आवश्यकता होगी।


2

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


प्रोजेक्ट Drupal 7 के लिए बनाया गया था। मेरे मॉड्यूल के कुछ हिस्सों को पढ़ने के मूल्यों के लिए सीधे Drupal DB संरचना में हेरफेर करने के लिए बनाया गया था और sql प्रश्नों को खोजने के लिए EntityFieldQueries की तुलना में बहुत तेज़ थे।
एलार

2

मैं यह field_attach_updateभी सुझाव देता हूं , और प्रत्यक्ष एसक्यूएल क्वेरी नहीं, क्योंकि एसक्यूएल नोड कैश ऑब्जेक्ट को अपडेट नहीं करता है, और आपके अगले में node_loadआप अपडेट किए गए फ़ील्ड मान को लोड नहीं करेंगे, आप पुराने मूल्य को लोड करेंगे।

field_attach_update प्रत्यक्ष SQL क्वेरी से बहुत बेहतर है।


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

1
अयश विधि (नया stdClass आदि ...) द्वारा केवल एक नोड को सहेजना संभव है, केवल UI आवश्यक फ़ील्ड पर मान्य बनाता है
pico34

मैं सभी क्षेत्रों को सेट किए बिना नोड को इस पद्धति से अपडेट करने की कोशिश करूंगा और जांच करूंगा कि क्या होगा। मॉड्यूल अपडेट प्रक्रिया (बैच) में नोड्स को अपडेट करने के लिए यह सबसे तेज़ तरीका हो सकता है।
एलोआर

2

जब तक मुझे यह लेख नहीं मिला, अन्य उत्तरों में बताए गए सभी तरीकों को आजमाने के बाद मुझे बहुत धीमा अपडेट टाइम मिला (एक नोड प्रकार के 700.000 नोड्स के लिए 20+ फ़ील्ड्स) । ब्लॉग / केवल-अद्यतन-परिवर्तित-फ़ील्ड्स या-गुण-संस्था-ड्रुपल

हुक_अपडेट में नीचे दिए गए कोड जैसा कुछ लागू करने के बाद मैंने अपडेट का समय घटाकर 2 घंटे कर दिया, जो मुझे लगता है कि प्रबंधनीय है।

if (!isset($sandbox['storage']['nids'])) {
    $sandbox['storage']['nids'] = [];
    $query = 'SELECT {nid} FROM node WHERE type = \'article\';';
    $result = db_query($query)->fetchCol();
    if ($result) {
      $sandbox['storage']['nids'] = $result;
      $sandbox['storage']['total'] = count($sandbox['storage']['nids']);
      $sandbox['storage']['last_run_time'] = time();
      $sandbox['progress'] = 0;
    }
  }

  $amount = 300;
  $nids = array_slice($sandbox['storage']['nids'], 0, $amount);

  if (!empty($nids)) {
    $nodes = node_load_multiple($nids, [], TRUE);
    foreach ($nodes as $node) {
      // Lets manipualte the entity.
      $article_wrapper = UtilsEntity::entity_metadata_wrapper('node', $node);
      // Eventual logic here.

        // Field to update
        $article_wrapper->my_field = 'my_value';
        $article_wrapper->save();

    $sandbox['progress']++;
    }
    $sandbox['message'] = 'Runs left: ' . (($sandbox['storage']['total'] - $sandbox['progress'])/$amount) . ' Progress: ' . (($sandbox['progress'] * $amount)/$sandbox['storage']['total']) . '%';
    $sandbox['storage']['last_run_time'] = time();
    unset($nids);
  }
  $sandbox['storage']['nids'] = array_slice($sandbox['storage']['nids'], 100, count($sandbox['storage']['nids']));
  if (!empty($sandbox['storage']['total'])) {
    $sandbox['#finished'] = ($sandbox['storage']['total'] - count($sandbox['storage']['nids'])) / $sandbox['storage']['total'];
  }
  return $sandbox['message'];

1

मुझे विशेष सामग्री प्रकार के सभी नोड्स के लिए एक क्षेत्र को अपडेट करने की समान आवश्यकता थी। मैंने node_load_multiple और field_attach_update का उपयोग किया ।

$nodes = node_load_multiple(array(), array('type' => 'content_type_name'));
foreach ($nodes as $node) {
  $node->field_name['und'][0]['value'] = 'field value';
  field_attach_update('node', $node);
}

मैंने इसे ड्रश के माध्यम से चलाया और यह बहुत तेज था।


0

क्या आपने इन अपडेट को सीधे mySQL का उपयोग करके डेटाबेस में करने पर विचार किया है? यह संभवतः सबसे सरल और तेज़ तरीका है जिसे आप प्राप्त करना चाहते हैं।

ये रहा एक सरल उदाहरण। आप phpMyAdmin में 'SQL' टैब से ऐसी कमांड निष्पादित कर सकते हैं। कल्पना करें कि आपके पास सदस्य प्रोफ़ाइल नामक एक सामग्री प्रकार है। इसमें आपके पास 'प्रकार का सदस्य' (जैसे कंपनी, व्यक्ति, संगठन) नाम का एक क्षेत्र है। मान लीजिए कि आप 'कंपनी' से 'कंपनी' के लिए सभी घटनाओं को अपडेट करना चाहते हैं। निम्नलिखित कमांड बस यही करेगा।

अद्यतन सामग्री_प्रकार_मैं_प्रतिष्ठित SET field_type_of_member_value= 'कंपनी' WHERE field_type_of_member_value= 'Company';

इसके अलावा, चेकआउट MySQL के साथ आरंभ करें


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

गूग बिंदु। मैंने अपने प्रारंभिक उत्तर में एक सरल उदाहरण जोड़ा।
Bisonbleu

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