2010-05-05 13 views
59

बस एक त्वरित सवाल है।पीडीओ :: fetchAll बनाम पीडीओ :: एक लूप में fetch

क्या पीडीओ :: fetchAll() और पीडीओ :: fetch() को लूप में (बड़े परिणाम सेट के लिए) का उपयोग करने के बीच कोई प्रदर्शन अंतर है?

मैं उपयोगकर्ता द्वारा परिभाषित कक्षा की वस्तुओं में ला रहा हूं, अगर इससे कोई फर्क पड़ता है।

मेरी प्रारंभिक अशिक्षित धारणा यह थी कि fetchAll तेज हो सकता है क्योंकि पीडीओ एक कथन में कई संचालन कर सकता है जबकि mysql_query केवल एक निष्पादित कर सकता है। हालांकि मुझे पीडीओ के आंतरिक कार्यों के बारे में बहुत कम ज्ञान नहीं है और दस्तावेज इस बारे में कुछ भी नहीं कहता है, और fetchAll() केवल एक PHP-side loop को सरणी में डाला गया है या नहीं।

कोई मदद? कि मैं सही पाए गए हैं पीएचपी के बारे में

+0

मैं नहीं जानता की स्मृति पदचिह्न में बड़ा फर्क देखेंगे, लेकिन मुझे संदेह है कि यह बेंचमार्क के लिए तुच्छ होगा। – Timothy

उत्तर

67

200k यादृच्छिक रिकॉर्ड के साथ छोटे बेंचमार्क। जैसा कि अपेक्षित है, fetchAll विधि तेज है लेकिन अधिक मेमोरी की आवश्यकता है।

Result : 
fetchAll : 0.35965991020203s, 100249408b 
fetch : 0.39197015762329s, 440b 

बेंचमार्क इस्तेमाल किया कोड:

<?php 
// First benchmark : speed 
$dbh = new PDO('mysql:dbname=testage;dbhost=localhost', 'root', ''); 
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
$sql = 'SELECT * FROM test_table WHERE 1'; 
$stmt = $dbh->query($sql); 
$data = array(); 
$start_all = microtime(true); 
$data = $stmt->fetchAll(); 
$end_all = microtime(true); 

$stmt = $dbh->query($sql); 
$data = array(); 
$start_one = microtime(true); 
while($data = $stmt->fetch()){} 
$end_one = microtime(true); 

// Second benchmark : memory usage 
$stmt = $dbh->query($sql); 
$data = array(); 
$memory_start_all = memory_get_usage(); 
$data = $stmt->fetchAll(); 
$memory_end_all = memory_get_usage(); 

$stmt = $dbh->query($sql); 
$data = array(); 
$memory_end_one = 0; 
$memory_start_one = memory_get_usage(); 
while($data = $stmt->fetch()){ 
    $memory_end_one = max($memory_end_one, memory_get_usage()); 
} 

echo 'Result : <br/> 
fetchAll : ' . ($end_all - $start_all) . 's, ' . ($memory_end_all - $memory_start_all) . 'b<br/> 
fetch : ' . ($end_one - $start_one) . 's, ' . ($memory_end_one - $memory_start_one) . 'b<br/>'; 
+28

आपका बेंचमार्क पूरी तरह से दोषपूर्ण है! आप अपने डेटा को दूसरे बेंचमार्क ('while' में) में $ डेटा सरणी में संग्रहीत नहीं करते हैं। क्या आपको सचमुच लगता है कि स्मृति अंतर इतना बड़ा है ?? वाह यह एक ** वास्तव में खराब जवाब ** है! – Rudie

+60

हाँ आप नहीं करते हैं। यह बेंचमार्क का लक्ष्य है: पहला आप एक fetch करते हैं तो फिर डेटा पर काम करते हैं। दूसरा, आप एक पंक्ति लाएंगे, इस पंक्ति पर काम करें, फिर अगली पंक्ति लाएं। डेटा टेबल प्रदर्शित करते समय एक अच्छा उदाहरण होगा, क्या आपको बफर में लिखने से पहले अपने सभी डेटा स्टोर करने की आवश्यकता है या नहीं? – Arkh

+1

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

9

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

+0

ऐसे समय होते हैं जहां PHP-buildin का उपयोग नहीं किया जाता है। जैसे एक क्रमबद्ध सरणी (बाइनरी खोज ftw) खोजना। – Reece45

+2

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

+0

@ AlReece45 आपने दो पूरी तरह से अलग-अलग कार्यों का वर्णन किया है। मैं PHP के 'सॉर्ट' का उपयोग कर PHP बनाम सॉर्ट फ़ंक्शन को पुन: कार्यान्वित करने के बारे में बात कर रहा था। @Byron मैं आपको लगता है कि fetchAll() का उपयोग अभी भी तेजी से हो जाएगा सब परिणामों को लाते समय मिल जाएगा दांव लगा रहा हूँ, लेकिन आप 'microtime (TRUE)' संदेह अगर आपके पास के साथ बेंचमार्क हो सकता था। –

8

@Arkh

// $data in this case is an array of rows; 

$data = $stmt->fetchAll(); 


// $data in this case is just one row after each loop; 

while($data = $stmt->fetch()){} 


// Try using 

$i = 0; 

while($data[$i++] = $stmt->fetch()){} 

स्मृति अंतर neglijable हो जाना चाहिए

+2

@stancu शीर्ष और निचले रूप प्रभावी रूप से समान हैं, और fetch() का उपयोग करके देखा गया अतिरिक्त एमईएम संभवतः() के ओवरहेड का आर्टिफैक्ट है। Fetch() का बिंदु एक समय में एक पंक्ति को संसाधित करना है, जबकि() को fetchAll (PDO :: FETCH_NUM) जैसी चीजों को पूरा करने के लिए मूर्खतापूर्ण है, क्योंकि आप पीडीओ में होने वाले सी-स्तरीय कंपाइलर ऑप्टिमाइज़ेशन को खो देते हैं मॉड्यूल। – DavidScherer

4

रूप मिहाई Stancu कह रहे थे, वहाँ लगभग कोई स्मृति का अंतर है यद्यपि fetch सभी धड़कता है + जबकि।

Result : 
fetchAll : 0.160676956177s, 118539304b 
fetch : 0.121752023697s, 118544392b 

मैं जबकि सही ढंग से चल रहा है के साथ ऊपर दिए गए परिणामों मिला:

$i = 0; 
while($data[$i++] = $stmt->fetch()){ 
    // 
} 

तो fetchAll कम स्मृति की खपत है, लेकिन लाने + जबकि तेजी से होता है! :)

+6

तेज? 0.16 ('fetchAll') बनाम 0.12 (' fetch') – Joost

+3

ओह, मैं थक गया हूँ .. संपादित। :} – Rihards

+1

काफी बड़े परिणाम सेट के साथ, आप PDOStatement :: fetch() और PDOStatement :: fetchALL() के बीच एक महत्वपूर्ण अंतर देखेंगे। "महत्वपूर्ण रूप से बड़ा" के रूप में योग्यता निर्धारित करने के लिए प्रत्येक पंक्ति के आकार पर निर्भर होगा। इसके अतिरिक्त, डिफ़ॉल्ट रूप से, PDOStatement :: Fetch()/fetchAll() fetch मोड पीडीओ :: FETCH_BOTH का उपयोग करता है जो प्रभावी रूप से प्रत्येक पंक्ति के आकार को दोगुना करता है, जिससे यह बड़े परिणाम सेट पर एमईएम उपयोग को कम करने में मदद कर सकता है। – DavidScherer

1

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

मेरा सुझाव है: थोड़ी देर के लिए कोड (बीटा में) चलाकर डेटा एकत्र करें और फिर अनुकूलन शुरू करें।

मेरे सरल बेंचमार्क (केवल परीक्षण निष्पादन समय) में मुझे 5% और 50% दोनों तरीकों के बीच अलग-अलग परिणाम मिल गए हैं। मैं एक ही स्क्रिप्ट में दोनों विकल्पों को चलाता हूं, लेकिन जब मैं fetch चलाता हूं + जबकि पहले यह fetchall से अधिक तेज़ होता है और इसके विपरीत। (मुझे पता है कि मुझे उन्हें सिंगल और दो सौ बार मेडियन और मतलब मिलना चाहिए था और फिर तुलना करना चाहिए, लेकिन जैसा कि मैंने शुरुआत में कहा है - मैंने निष्कर्ष निकाला है कि मेरे मामले में ऐसा करना शुरू करना बहुत जल्दी है।)

3

लेकिन निश्चित रूप से यदि आप किसी सरणी में प्राप्त डेटा संग्रहीत कर रहे हैं, तो स्मृति उपयोग बराबर होगा?

<?php 
define('DB_HOST', 'localhost'); 
define('DB_USER', 'root'); 
define('DB_PASS', ''); 
// database to use 
define('DB', 'test'); 
try 
{ 
    $dbh = new \PDO('mysql:dbname='. DB .';host='. DB_HOST, DB_USER, DB_PASS); $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
    $sql = 'SELECT * FROM users WHERE 1'; 
    $stmt = $dbh->query($sql); 
    $data = array(); 
    $start_all = microtime(true); 
    $data = $stmt->fetchAll(); 
    $end_all = microtime(true); 

    $stmt = $dbh->query($sql); 
    $data = array(); 
    $start_one = microtime(true); 
    while($data = $stmt->fetch()){} 
    $end_one = microtime(true); 

    // Second benchmark : memory usage 
    $stmt = $dbh->query($sql); 
    $data = array(); 
    $memory_start_all = memory_get_usage(); 
    $data = $stmt->fetchAll(); 
    $memory_end_all = memory_get_usage(); 

    $stmt = $dbh->query($sql); 
    $data = array(); 
    $memory_end_one = 0; 
    $memory_start_one = memory_get_usage(); 
    while($data[] = $stmt->fetch()){ 
    $memory_end_one = max($memory_end_one, memory_get_usage()); 
    } 

    echo 'Result : <br/> 
    fetchAll : ' . ($end_all - $start_all) . 's, ' . ($memory_end_all - $memory_start_all) . 'b<br/> 
    fetch : ' . ($end_one - $start_one) . 's, ' . ($memory_end_one - $memory_start_one) . 'b<br/>'; 
} 
catch (PDOException $e) 
{ 
    echo $e->getMessage(); 
} 
?> 

Result : 
fetchAll : 2.6941299438477E-5s, 9824b 
fetch : 1.5974044799805E-5s, 9824b 
4

"मेमोरी पदचिह्न" मापने वाले सभी बेंचमार्क बहुत सरल कारण के लिए वास्तव में गलत हैं।

पीडीओ डिफ़ॉल्ट रूप से स्मृति में सब बातों को लोड करता है और यह परवाह नहीं करता है, तो आप लाना या fetchAll का उपयोग करें। वास्तव में unbuffered क्वेरी के लाभ आप unbuffered प्रश्नों का उपयोग करने के लिए पीडीओ निर्देश देना चाहिए पाने के लिए:

$db->setAttribute(PDO::MYSQL_ATTR_USE_BUFFERED_QUERY, false);

उस मामले में आप स्क्रिप्ट

+0

buffered क्वेरी (डिफ़ॉल्ट) का उपयोग करते हुए '$ stmt-> fetch()' का उपयोग करते हुए और '$ stmt-> fetch()' का उपयोग करके अनबफर किए गए प्रश्नों के साथ क्या अंतर है ('PDO :: MYSQL_ATTR_USE_BUFFERED_QUERY' विशेषता 'झूठी पर सेट की गई है ')? मैंने देखा कि यदि आप डिफ़ॉल्ट buffered मोड का उपयोग करते हैं, तो '$ stmt-> fetch()' बहुत बड़ा डेटा सेट के लिए काम करता है जबकि 'stmt-> fetchAll()' स्मृति सीमा त्रुटि लौटा सकता है। तो '$ stmt-> fetch() 'kinda' unbuffered' है? – tonix

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