2010-03-10 6 views
32

मेरे पास MySQLi, क्वेरी, और संबंधित मेमोरी प्रबंधन का उपयोग करने के बारे में कुछ प्रश्न हैं।MySQLi क्वेरी परिणाम: सर्वश्रेष्ठ दृष्टिकोण, क्या आप दोनों को बंद कर देते हैं, मुफ़्त, दोनों?

@ $db = new mysqli($dbhost, $un, $ps, $dbname); 
$query = "SELECT field1, field2 ". 
     "FROM table1 ". 
     "WHERE field1={$some_value}"; 
$results = $db->query($query); 

while ($result = $results->fetch_object()) { 
    // Do something with the results 
} 

$query = "SELECT field1, field2 ". 
     "FROM table2 ". 
     "WHERE field1={$some_value2}"; 
// question 1 
$results = $db->query($query); 

while ($result = $results->fetch_object()) { 
    // Do something with the second set of results 
} 

// Tidy up, question 2 
if ($results) { 
    $results->free(); 
} 
if ($db) { 
    $db->close(); 
} 

// Question 3, a general one 

: कोड यहाँ सिर्फ मेरे सवालों का स्पष्ट करने के लिए है, तो त्रुटि जाँच, आदि मुझे पता है कि किया जाना :)

मान लीजिए मैं इस तरह कुछ है की जरूरत के लिए उस पर डंप नहीं है तो, इसके बाद के संस्करण कोड में टिप्पणी के आधार पर, यहाँ मेरे सवालों हैं:

  1. जब मैं $results से पीछे नहीं क्वेरी के परिणामों असाइन करते हैं, क्या पिछले परिणामों के साथ जुड़े स्मृति का क्या होगा? क्या मुझे नया कार्य सौंपने से पहले परिणाम मुक्त करना चाहिए?

  2. 1 करने के लिए संबंधित है, जब मैं अंत में साफ करते हैं, अभी पिछले परिणाम पर्याप्त सफाई की जाती है?

  3. जब मैं एक परिणाम को साफ करने, मैं के रूप में ऊपर यह मुक्त कराने की जानी चाहिए, कोशिश करते हैं मैं इसे बंद करने दिया जाना चाहिए, या दोनों?

मैं 3 सवाल पूछने क्योंकि mysqli::query के लिए PHP प्रलेखन एक उदाहरण पास का उपयोग करता है, भले ही करीब mysqli_result का हिस्सा (mysqli::query में उदाहरण 1 देखें) नहीं है। और इसके विपरीत, मेरा सामान्य PHP संदर्भ पाठ free (PHP और MySQL वेब विकास, चौथा संस्करण, वेलिंग और थॉमसन) का उपयोग करता है।

+3

आप उस पल को जानते हैं जब आपने किसी प्रोजेक्ट पर काम करने के बाद उम्र बढ़ाई है और आप केवल एक प्रश्न के उत्तर के लिए स्टैक ओवरफ्लो को जांचने का निर्णय लेते हैं कि आप पहले से ही पूछ चुके हैं और उस प्रश्न का उत्तर साल पहले हुआ था ...? उह ... मुझे बूढ़ा होना चाहिए :) नीचे फिर से महान उत्तरों के लिए धन्यवाद। –

उत्तर

48

जब मैं $results को दूसरी क्वेरी के परिणामों असाइन करते हैं, क्या पिछले परिणामों के साथ जुड़े स्मृति को क्या होता है?

जब आप इस पर अमल:

$results = $db->query($query); 

अगर वहाँ $results में कुछ था से पहले, इस पुरानी सामग्री अब और नहीं पहुँचा जा सकता, कोई संदर्भ यह करने के लिए छोड़ दिया है के रूप में।

ऐसे मामले में, PHP वैरिएबल की पुरानी सामग्री को के रूप में चिह्नित नहीं करेगा, "- और PHP को कुछ स्मृति की आवश्यकता होने पर इसे स्मृति से निकाल दिया जाएगा।

यह, कम से कम, सामान्य PHP चर के लिए सच है; SQL क्वेरी से परिणामों के मामले में, हालांकि, कुछ डेटा को ड्राइवर-स्तर पर स्मृति में रखा जा सकता है - जिस पर PHP का अधिक नियंत्रण नहीं होता है।


मैं नए एक सौंप पहले कि परिणाम को मुक्त किया जाना चाहिए?

मैं ऐसा कभी नहीं है कि - लेकिन, mysqli_result::free के मैनुअल पृष्ठ उद्धृत:

नोट: जब आपके परिणाम वस्तु की जरूरत नहीं है तुम हमेशा मुक्त mysqli_free_result के साथ अपने परिणाम() चाहिए अब

यह शायद एक छोटे से स्क्रिप्ट ... और एक ही तरीका है यकीन है कि परीक्षण करने के लिए किया जाएगा होने के लिए कोई फर्क नहीं पड़ता, इससे पहले कि और कहा कि metho बुला के बाद memory_get_usage का उपयोग कर डी, यह देखने के लिए कि कोई अंतर है या नहीं।


संबंधित 1 करने के लिए, जब मैं अंत में साफ करते हैं, अभी पिछले परिणाम पर्याप्त सफाई की जाती है?

जब स्क्रिप्ट अंत:

  • डेटाबेस के लिए कनेक्शन बंद कर दिया जाएगा - जो किसी भी याद है कि चालक द्वारा इस्तेमाल किया जा सकता है मुक्त कर दिया जाना चाहिए
  • सभी पीएचपी द्वारा इस्तेमाल किया चर का मतलब लिपि नष्ट हो जाएगी - जिसका अर्थ है कि वे जिस स्मृति का उपयोग कर रहे थे उसे मुक्त किया जाना चाहिए।

तो, स्क्रिप्ट के अंत में, परिणामस्वरूप वास्तव में परिणाम मुक्त करने की आवश्यकता नहीं है।


जब मैं एक परिणाम को साफ करने की कोशिश करते हैं, मैं इसे के रूप में ऊपर मुक्त कराने की जानी चाहिए, मैं इसे बंद करने दिया जाना चाहिए, या दोनों?

आप डेटाबेस के लिए कनेक्शन बंद करते हैं (mysqli::close का उपयोग कर आप की तरह प्रस्तावित), यह आपके डेटाबेस से डिस्कनेक्ट कर देगा।

जिसका अर्थ है कि यदि आप एक और क्वेरी करना चाहते हैं तो आपको पुनः कनेक्ट करना होगा! जो पर अच्छा नहीं है (कुछ समय, संसाधन, ...)

आम तौर पर, मैं डेटाबेस से कनेक्शन बंद नहीं करता जब तक कि मुझे सच में यकीन नहीं है कि मुझे अब इसकी आवश्यकता नहीं होगी - जिसका अर्थ है कि मैं स्क्रिप्ट के अंत से पहले डिस्कनेक्ट नहीं करूँगा।

और के रूप में "स्क्रिप्ट की अंत" का अर्थ है "कनेक्शन बंद कर दिया जाएगा" भले ही आप इसे निर्दिष्ट नहीं करते हैं; मैं लगभग कनेक्शन को बंद नहीं करता हूं।

+3

वाह! यह एक उत्कृष्ट और बहुत अच्छी तरह से लिखित और सूचनात्मक उत्तर है। ठीक वही जो मेरे द्वारा खोजा जा रहा था। धन्यवाद! मुझे लगता है कि सब कुछ मैं उस भाषा के लिए अत्यधिक चिंतित हूं जो कचरा संग्रह को संभालता है। एक बार फिर धन्यवाद! –

+0

आपका स्वागत है :-) ;;; ठीक है, आप कचरा संग्रह के बारे में सच हो सकते हैं - लेकिन यह भी न भूलें कि PHP का प्राथमिक उपयोग उन स्क्रिप्ट्स के लिए है जो शायद ही कभी कुछ सेकंड से अधिक समय तक चलते हैं - जिसका अर्थ है कि कुछ स्मृति रिसाव भी है, लेकिन यह आमतौर पर नहीं है वह गलत है। –

+0

अच्छा बिंदु। मैं अभी भी वेब विकास की दुनिया में एक "रोमांचकारी" हूं, इसलिए शायद पुराने संकलित भाषाओं का उपयोग करने के मेरे अतीत में मुझे स्मृति प्रबंधन की बात आती है जब मुझे असमान रूप से डर लगता है! :) –

-3

सामान्य PHP तरीका किसी भी खुले संसाधन को बंद नहीं करना है। सब कुछ स्क्रिप्ट अंत में स्वचालित रूप से बंद हो जाएगा। केवल मामले में जहां आप मैन्युअल पास की देखभाल करने के लिए है अगर आप लंबे भारी कोड चलाने के लिए है, जो PHP के लिए बहुत आम नहीं है है।

+2

धन्यवाद, यह आसान बनाता है। हालांकि, mysqli_result के हिस्से के रूप में भाषा में निःशुल्क क्यों शामिल है? क्या यह एक विरासत चीज है? –

13

पहले से दिए गए उत्तरों अच्छे हैं, लेकिन मैं एक बिंदु जोड़ना और एक और स्पष्टीकरण देना चाहता था।

सबसे पहले, स्पष्टीकरण। क्लोज़() विधि के उपयोग के संबंध में, यह ध्यान रखना महत्वपूर्ण है कि ओपी mysqli_result वर्ग की नज़दीकी() विधि का संदर्भ दे रहा था, न कि mysqli वर्ग।परिणाम वर्ग में, क्लोज़() विधि केवल() विधि के लिए उपनाम है, जैसा कि documentation में दिखाया गया है, जबकि mysqli वर्ग में, यह कनेक्शन बंद कर देता है। इस प्रकार, अगर वांछित हो तो मुफ्त() के स्थान पर नजदीकी() का उपयोग करना ठीक है।

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

0

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

$db = NULL; 
try { 
    $dbPool = "p:$dbhost"; // question 3: use pooling 
    $db = new mysqli($dbPool, $un, $ps, $dbname); 
    if ($db->connect_errno) { 
     throw new Exception('' . $db->connect_error . ' ' . $db->connect_errno 
       . "\n" . $un . '@' . $dbhost . ' ' . $dbname); 
     // NOTE: It's commonly considered a security 
     // risk to output connection information e.g. 
     // host, user and database names. 
    } 

    $query = "SELECT field1, field2 ". 
      "FROM table1 ". 
      "WHERE field1={$some_value}"; 

    $results = NULL; 
    try { 

     if (!$results = $db->query($query)) { 
      throw new Exception($db->error . " " . $db->errno 
        . "\n" . $query); 
      // NOTE: It's commonly considered a security 
      // risk to output SQL ($query). 
     } 
     while ($result = $results->fetch_object()) { 
      // Do something with the results 
     } 

    } catch (Exception $ex) { 
     // log, report, or otherwise handle the error 
    } 
    if ($results) { 
     $results->free(); // question 1: why risk it? 
    } 

    $query = "SELECT field1, field2 ". 
      "FROM table2 ". 
      "WHERE field1={$some_value2}"; 

    $results = NULL; 
    try { 

     if (!$results = $db->query($query)) { 
      throw new Exception($db->error . " " . $db->errno 
        . "\n" . $query); 
      // NOTE: It's commonly considered a security 
      // risk to output SQL ($query). 
     }    
     while ($result = $results->fetch_object()) { 
      // Do something with the second set of results 
     } 

    } catch (Exception $ex) { 
     // log, report, or otherwise handle the error 
    } 
    if ($results) { 
     $results->free(); // question 2: again, why risk it? 
    } 

} catch (Exception $ex) { 
    // log, report, or otherwise handle the error 
} 
if ($db) { 
    $db->close(); 
} 

मेरी राय में, कनेक्शन पूलिंग एक स्मृति रिसाव के लिए संभावना बढ़ जाती है, लेकिन पुस्तिका के अनुसार, कनेक्शन पूलिंग पुस्तकालयों सफाई का एक बहुत करते हैं आपके लिए स्वचालित रूप से:

mysqli एक्सटेंशन का लगातार कनेक्शन हालांकि अंतर्निहित क्लीनअप हैंडलिंग कोड प्रदान करता है। सफाई mysqli द्वारा किए गए शामिल हैं:

रोलबैक सक्रिय लेनदेन

बंद और ड्रॉप अस्थायी तालिकाओं

अनलॉक टेबल

रीसेट सत्र चर

बंद तैयार बयान (हमेशा पीएचपी के साथ होता है)

बंद हैंडलर

रिलीज ताले GET_LOCK के साथ प्राप्त()

यह सुनिश्चित करता है कि लगातार कनेक्शन से पहले ग्राहक की प्रक्रिया उन्हें का उपयोग करता है, कनेक्शन पूल से वापसी पर एक साफ राज्य में हैं।

स्रोत:http://php.net/manual/en/mysqli.persistconns.php

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

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^