2010-01-25 11 views
9

मैं अर्ध-सरल डेटाबेस रैपर क्लास लिख रहा हूं और एक fetching विधि चाहता हूं जो स्वचालित रूप से संचालित करेगी: इसे प्रत्येक अलग-अलग कथन को केवल पहली बार तैयार करना चाहिए चारों ओर बस और लगातार कॉल पर क्वेरी को बाध्य और निष्पादित करें।PHP पीडीओ: प्रदर्शन को फिर से तैयार करने के तरीके को कैसे प्रभावित करता है

मुझे लगता है कि मुख्य प्रश्न यह है: एक ही MySQL कथन कार्य को फिर से तैयार करने के लिए, क्या पीडीओ जादुई रूप से बयान को पहचान लेगा (इसलिए मुझे नहीं करना है) और ऑपरेशन को रोकना है? अपनी अनूठी कुंजी के अंतर्गत -

तो नहीं, मैं प्रत्येक अलग क्वेरी के लिए एक अद्वितीय कुंजी उत्पन्न करके ऐसा करने को प्राप्त करने और डेटाबेस वस्तु में एक निजी सरणी में तैयार बयान रखने के लिए योजना बना रहा हूँ। मैं निम्नलिखित तरीकों में से एक में सरणी कुंजी प्राप्त करने की योजना बना रहा हूं (जिसमें से कोई भी मुझे पसंद नहीं है)। वरीयता के क्रम में: - अगर हमारे विधि एक पाश के भीतर कहा जाता है basename(__FILE__, ".php") . __LINE__ की तर्ज पर कुछ (इस विधि केवल काम करेगा -

  • प्रोग्रामर जब विधि बुला एक अतिरिक्त, हमेशा एक ही पैरामीटर पारित किया है जो है मामले की अधिकांश कार्यक्षमता की आवश्यकता होती है)
  • प्रोग्रामर एक अतिरिक्त पैरामीटर
  • कुंजी उत्पन्न करने के लिए पास की गई क्वेरी का उपयोग करने के लिए पूरी तरह से यादृच्छिक स्ट्रिंग (सबसे पहले जेनरेट किया गया) पास करता है - हैश का प्राप्त करना क्वेरी या कुछ समान
  • कैल द्वारा पहली बुलेट (उपरोक्त) के समान प्राप्त करें लिंग debug_backtrace

क्या कोई भी इसी तरह का अनुभव है? यद्यपि मैं के लिए काम कर रहा हूं, अनुकूलन पर कुछ ध्यान देने योग्य है (यह सप्ताह के दौरान काफी बड़ा और बढ़ रहा है), शायद मैं कुछ भी नहीं कर रहा हूं और जो भी कर रहा हूं, उसमें कोई प्रदर्शन लाभ नहीं है?

+0

मुझे लगता है कि एसक्यूएल के साथ कुंजी के साथ तैयार कथन हैंडल डालना, केवल एकमात्र रास्ता है। मुझे आपके द्वारा प्रस्तावित अन्य तरीकों में कोई लाभ नहीं दिख रहा है। हालांकि, मुझे आश्चर्य है कि क्या पीडीओ स्वचालित रूप से इस अनुकूलन को बनाता है ... – Inshallah

+0

हालांकि यदि क्वेरी लंबी है और इसे हजारों बार कहा जाता है, तो सरणी में ऐसी कुंजी का लुकअप अपने आईएमओ पर एक बाधा बन जाएगा। – raveren

+0

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

उत्तर

1

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

$ php -v 
$ PHP 5.3.0-3 with Suhosin-Patch (cli) (built: Aug 26 2009 08:01:52) 
$ ... 
$ php benchmark.php 
$ PHP hashing: 0.19465494155884 [microtime] 
$ MD5 hashing: 0.57781004905701 [microtime] 
$ 799994 

कोड:

<?php 
error_reporting(E_ALL); 

$queries = array("SELECT", 
       "INSERT", 
       "UPDATE", 
       "DELETE", 
       ); 
$query_length = 256; 
$num_queries = 256; 
$iter = 10000; 

for ($i = 0; $i < $num_queries; $i++) { 
    $q = implode('', 
      array_map("chr", 
      array_map("rand", 
         array_fill(0, $query_length, ord("a")), 
         array_fill(0, $query_length, ord("z"))))); 
    $queries[] = $q; 
} 

echo count($queries), "\n"; 

$cache = array(); 
$side_effect1 = 0; 
$t = microtime(true); 
for ($i = 0; $i < $iter; $i++) { 
    foreach ($queries as $q) { 
     if (!isset($cache[$q])) { 
      $cache[$q] = $q; 
     } 
     else { 
      $side_effect1++; 
     } 
    } 
} 
echo microtime(true) - $t, "\n"; 

$cache = array(); 
$side_effect2 = 0; 
$t = microtime(true); 
for ($i = 0; $i < $iter; $i++) { 
    foreach ($queries as $q) { 
     $md5 = md5($q); 
     if (!isset($cache[$md5])) { 
      $cache[$md5] = $q; 
     } 
     else { 
      $side_effect2++; 
     } 
    } 
} 
echo microtime(true) - $t, "\n"; 

echo $side_effect1 + $side_effect2, "\n"; 
+0

बेंचमार्क के लिए धन्यवाद, दुख की बात है कि मैं इसे यहां काम करने के लिए नहीं मिला क्योंकि $ कैश का कोई डेटा कभी नहीं था और $ q केवल "DELETEArray" था, लेकिन जैसे ही मुझे अवसर है – dbemerlin

+0

@ डीबेमेरिन, हां, माफ़ कीजिये। यह अब काम करना चाहिए। मैंने Emacs से प्रतिलिपि/चिपकाने के बाद कोड को थोड़ा सा संपादित किया, प्रक्रिया में कुछ त्रुटियों को प्रस्तुत किया :-)। – Inshallah

+0

मैंने अब उन संशोधनों के साथ आपकी स्क्रिप्ट के आधार पर इसका परीक्षण किया: $ 100 क्वेरीज़ से यादृच्छिक स्ट्रिंग को 20 बार जोड़कर 100 यादृच्छिक तार बनाएं। इन यादृच्छिक तारों का पूर्वानुमान $ iter बार लूप करें और प्रत्येक बार यह जांचें कि स्ट्रिंग $ कैश में मौजूद है या नहीं, अगर इसे सेट नहीं किया गया है। एमडी 5 के लिए: यादृच्छिक तारों का foreach हैश बनाते हैं और फिर $ iter बार लूप और वही करते हैं। परिणाम: $ iter = 1 के साथ md5 हैश 0.00008ms धीमी है, $ iter (100 और निचले) के कम मूल्यों के लिए कोई वास्तविक प्रदर्शन अंतर नहीं है (<0.1s), पुनरावृत्तियों की बढ़ती मात्रा एमडी 5 लाभ अधिक लाभ के साथ। इसलिए: उपयोग-मामले पर निर्भर करता है। – dbemerlin

1

मेरे ज्ञान के लिए पीडीओ पहले से ही तैयार कथन का पुन: उपयोग नहीं करता है क्योंकि यह स्वयं क्वेरी से विश्लेषण नहीं करता है, इसलिए यह नहीं जानता कि यह वही प्रश्न है या नहीं।

यदि आप तैयार प्रश्नों का कैश बनाना चाहते हैं, तो सबसे आसान तरीका imho क्वेरी स्ट्रिंग md5-हैश होगा और एक लुकअप तालिका उत्पन्न करेगा।

ओटीओएच: आप कितने प्रश्न निष्पादित कर रहे हैं (प्रति मिनट)? यदि कुछ सौ से भी कम है तो आप केवल कोड को जटिल करते हैं, प्रदर्शन लाभ मामूली होगा।

+0

मुझे कुछ याद आ रहा है, लेकिन क्वेरी स्ट्रिंग का md5 क्यों बनाएं? क्वेरी स्ट्रिंग _itself_ का उपयोग क्यों नहीं करें? – Inshallah

+0

क्योंकि क्वेरी स्ट्रिंग स्वयं काफी लंबी हो सकती है, इसलिए एक लुकअप धीमा हो जाएगा। एक हैश त्वरित लुकअप की अनुमति देगा (बेशक यदि प्रश्न पर्याप्त कम हैं और लुकअप पर्याप्त हैं तो यह वास्तव में धीमा हो सकता है लेकिन सामान्य स्थिति में हैश खोज तेज है) – dbemerlin

+0

क्या? प्रदर्शन के लिए क्वेरी स्ट्रिंग MD5ing? यह पूरी तरह से पागल है :-)। मैंने पर्ल में प्रयुक्त क्वेरी स्ट्रिंग विधि द्वारा अच्छा प्रभाव डालने के लिए अनुक्रमण को देखा है। क्या आप वाकई इस तरह की सिफारिश करने के लिए PHP arrays को लागू करने के तरीके के बारे में पर्याप्त जानते हैं? – Inshallah

4

मेरा विश्वास करो, मैं पहले और तैयार बयान प्रदर्शन लाभ था की एक कैश के निर्माण के बाद यह कर दिया है बहुत ध्यान देने योग्य - इस सवाल देखें: Preparing SQL Statements with PDO

function DB($query) 
{ 
    static $db = null; 
    static $result = array(); 

    if (is_null($db) === true) 
    { 
     $db = new PDO('sqlite:' . $query, null, null, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING)); 
    } 

    else if (is_a($db, 'PDO') === true) 
    { 
     $hash = md5($query); 

     if (empty($result[$hash]) === true) 
     { 
      $result[$hash] = $db->prepare($query); 
     } 

     if (is_a($result[$hash], 'PDOStatement') === true) 
     { 
      if ($result[$hash]->execute(array_slice(func_get_args(), 1)) === true) 
      { 
       if (stripos($query, 'INSERT') === 0) 
       { 
        return $db->lastInsertId(); 
       } 

       else if (stripos($query, 'SELECT') === 0) 
       { 
        return $result[$hash]->fetchAll(PDO::FETCH_ASSOC); 
       } 

       else if ((stripos($query, 'UPDATE') === 0) || (stripos($query, 'DELETE') === 0)) 
       { 
        return $result[$hash]->rowCount(); 
       } 

       else if (stripos($query, 'REPLACE') === 0) 
       { 
       } 

       return true; 
      } 
     } 

     return false; 
    } 
} 

जब से मैं प्रश्नों में टकराव के बारे में चिंता करने की जरूरत नहीं है, मैं md5()sha1() के बजाय का उपयोग कर समाप्त हो गया है:

एक इस कोड को मैं के बाद आया था, कैश्ड तैयार बयानों के साथ किया गया था।

+0

मुझे यह जानने में बहुत दिलचस्पी है कि आपने एमडी 5 हैशिंग का उपयोग करने का निर्णय क्यों लिया। मैंने एमडी 5 हैशिंग बनाम PHP देशी सरणी के एक बेवकूफ बेंचमार्क पोस्ट किया है, और एमडी 5 विधि के साथ कोई सुधार मिल सकता है। – Inshallah

+0

@ इंशल्लाह: 'md5()' का उपयोग करने का निर्णय बस इतना था कि मेरे पास प्रश्नों में नई लाइनें ('\ n') नहीं थीं। –

6

MySQL (सबसे डीबीएमएस की तरह), तैयार बयानों के लिए निष्पादन की योजना कैश होगा इसलिए यदि उपयोगकर्ता एक के लिए एक योजना बनाता है:

SELECT * FROM some_table WHERE a_col=:v1 AND b_col=:v2 

(जहां v1 और v2 बाँध वार्स कर रहे हैं) तो मूल्यों से अंतर्वेशित जा करने के लिए भेजता है डीबीएमएस, फिर उपयोगकर्ता बी एक ही प्रश्न भेजता है (लेकिन इंटरपोलेशन के लिए अलग-अलग मानों के साथ) डीबीएमएस को योजना को पुन: उत्पन्न करने की आवश्यकता नहीं है। यानी यह डीबीएमएस है जो मिलान योजना ढूंढता है - पीडीओ नहीं।

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

मुख्य सवाल यह है कि क्या यह योजना पहली जगह में योजना बनाने की लागत से अधिक है।

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

इसे स्वयं मापने का प्रयास करें (संकेत: आप धीमी क्वेरी थ्रेसहोल्ड 0 पर सेट करना चाहते हैं और लॉग को लिखे गए प्रश्नों के लिए शाब्दिक मानों को अनाम रूपों में परिवर्तित करने के लिए कुछ कोड लिखना चाहते हैं)।

+0

-1 [तैयार वक्तव्य और संग्रहीत कार्यक्रमों के कैशिंग] के तहत दस्तावेज के रूप में (http://dev.mysql.com/doc/en/statement-caching.html): "* सर्वर तैयार कथन और संग्रहीत कार्यक्रमों के लिए कैश बनाए रखता है एक सत्र के आधार पर। एक सत्र के लिए कैश किए गए विवरण अन्य सत्रों तक पहुंच योग्य नहीं होते हैं। जब कोई सत्र समाप्त होता है, तो सर्वर इसके लिए कैश किए गए किसी भी बयान को त्याग देता है। * "शायद भ्रम उत्पन्न हुआ क्योंकि तैयार कथन पोस्ट-वेरिएबल विस्तार सामान्य में कैश किए जाते हैं जिस तरह से [कैसे क्वेरी कैश ऑपरेट करता है] के तहत दस्तावेज किया गया है (http://dev.mysql.com/doc/en/query-cache-operation.html)? – eggyal

0

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

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