पीडीओ की क्वेरी बनाम निष्पादित


129

क्या वे दोनों एक ही काम करते हैं, केवल अलग-अलग तरीके से?

क्या इसके prepareबीच उपयोग करने के अलावा कोई अंतर है

$sth = $db->query("SELECT * FROM table");
$result = $sth->fetchAll();

तथा

$sth = $db->prepare("SELECT * FROM table");
$sth->execute();
$result = $sth->fetchAll();

?

जवाबों:


145

query एक मानक एसक्यूएल स्टेटमेंट चलाता है और आपको एसक्यूएल इंजेक्शन और अन्य मुद्दों से बचने के लिए सभी डेटा को ठीक से बचाना पड़ता है।

executeएक तैयार बयान चलाता है जो आपको मापदंडों से बचने या उद्धृत करने की आवश्यकता से बचने के लिए मापदंडों को बांधने की अनुमति देता है। executeयदि आप कई बार क्वेरी दोहरा रहे हैं तो भी बेहतर प्रदर्शन करेंगे। तैयार कथनों का उदाहरण:

$sth = $dbh->prepare('SELECT name, colour, calories FROM fruit
    WHERE calories < :calories AND colour = :colour');
$sth->bindParam(':calories', $calories);
$sth->bindParam(':colour', $colour);
$sth->execute();
// $calories or $color do not need to be escaped or quoted since the
//    data is separated from the query

सबसे अच्छा अभ्यास तैयार बयानों और executeबढ़ी हुई सुरक्षा के साथ रहना है

यह भी देखें: क्या SQL इंजेक्शन को रोकने के लिए PDO तैयार किए गए कथन पर्याप्त हैं?


लिंक काफी बेवकूफ जवाब के साथ सवाल की ओर जाता है, पहले से ही टिप्पणियों में आलोचना की गई है।
आपका कॉमन सेंस

इसलिए यदि आप एक तैयारी का उपयोग करते हैं, तो इंजेक्शन को रोकने : calories के mysql_real_escape_string()लिए उस तरह का समान है या क्या आपको $sth->bindParam(':calories', $calories);सुरक्षा बढ़ाने के लिए ज़रूरत से ज़्यादा ज़रूरत है ?
दान

क्यों करता है queryएक वापसी PDOStatement , एक के बजाय bool की तरह execute?
सिंह


47

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

$sth = $db->prepare("SELECT * FROM table WHERE foo = ?");
$sth->execute(array(1));
$results = $sth->fetchAll(PDO::FETCH_ASSOC);

$sth->execute(array(2));
$results = $sth->fetchAll(PDO::FETCH_ASSOC);

वे आम तौर पर आपको एक प्रदर्शन सुधार देंगे, हालांकि छोटे पैमाने पर ध्यान देने योग्य नहीं। तैयार कथनों (MySQL संस्करण) पर अधिक पढ़ें


मुझे यह पसंद है कि जिस तरह से आपने बताया कि यह तेजी से क्यों होगा।
टिफ़रिली


3

गिलियन का जवाब बहुत अच्छा है, लेकिन मैं सिर्फ यह जोड़ना चाहता था कि कभी-कभी सर्वोत्तम प्रथाओं के लिए दुर्लभ अपवाद होते हैं, और आप अपने पर्यावरण को दोनों तरीकों से देखना चाहते हैं कि सबसे अच्छा काम क्या होगा।

एक मामले में, मैंने पाया कि queryमेरे उद्देश्यों के लिए तेजी से काम किया क्योंकि मैं एमएस SQL ​​सर्वर के लिए खराब समर्थित Microsoft ODBC ड्राइवर के साथ PHP7 चल रहे उबंटू लिनक्स बॉक्स से भरोसेमंद डेटा स्थानांतरित कर रहा था ।

मैं इस सवाल पर पहुंचा क्योंकि मेरे पास एक ईटीएल के लिए एक लंबी चलने वाली स्क्रिप्ट थी जिसे मैं गति के लिए निचोड़ने की कोशिश कर रहा था। यह मेरे लिए सहज ज्ञान युक्त लग रहा था, जो दो की बजाय केवल एक फ़ंक्शन को कॉल कर रहा था और इससे queryअधिक तेज़ हो सकता है । पैरामीटर बाइंडिंग ऑपरेशन उत्कृष्ट सुरक्षा प्रदान करता है, लेकिन यह महंगा हो सकता है और संभवतः अनावश्यक होने से बचा जा सकता है।prepareexecute

कुछ दुर्लभ स्थितियों को देखते हुए :

  1. यदि आप तैयार कथन का पुनः उपयोग नहीं कर सकते क्योंकि यह Microsoft ODBC ड्राइवर द्वारा समर्थित नहीं है

  2. यदि आप इनपुट के बारे में चिंतित नहीं हैं तो इनपुट और सरल पलायन स्वीकार्य है। यह मामला हो सकता है क्योंकि कुछ डेटासेट को बाइंड करना Microsoft ODBC ड्राइवर द्वारा समर्थित नहीं है

  3. PDO::lastInsertId Microsoft ODBC ड्राइवर द्वारा समर्थित नहीं है।

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

शुरू करने के लिए, मैंने Microsoft SQL सर्वर में एक मूल तालिका बनाई है

CREATE TABLE performancetest (
    sid INT IDENTITY PRIMARY KEY,
    id INT,
    val VARCHAR(100)
);

और अब प्रदर्शन मैट्रिक्स के लिए एक बुनियादी समयबद्ध परीक्षण।

$logs = [];

$test = function (String $type, Int $count = 3000) use ($pdo, &$logs) {
    $start = microtime(true);
    $i = 0;
    while ($i < $count) {
        $sql = "INSERT INTO performancetest (id, val) OUTPUT INSERTED.sid VALUES ($i,'value $i')";
        if ($type === 'query') {
            $smt = $pdo->query($sql);
        } else {
            $smt = $pdo->prepare($sql);
            $smt ->execute();
        }
        $sid = $smt->fetch(PDO::FETCH_ASSOC)['sid'];
        $i++;
    }
    $total = (microtime(true) - $start);
    $logs[$type] []= $total;
    echo "$total $type\n";
};

$trials = 15;
$i = 0;
while ($i < $trials) {
    if (random_int(0,1) === 0) {
        $test('query');
    } else {
        $test('prepare');
    }
    $i++;
}

foreach ($logs as $type => $log) {
    $total = 0;
    foreach ($log as $record) {
        $total += $record;
    }
    $count = count($log);
    echo "($count) $type Average: ".$total/$count.PHP_EOL;
}

मैंने अपने विशिष्ट वातावरण में कई अलग-अलग परीक्षण किए हैं और मायने रखता है, और लगातार 20-30% queryसे prepare/ के साथ तेजी से परिणाम प्राप्त करते हैंexecute

5.8128969669342 तैयार
5.8688418865204 तैयार
4.2948560714722 क्वेरी
4.9533629417419 क्वेरी
5.9051351547241 तैयार
४.३३२१०२०६०३१८ क्वेरी
5.9672858715057 तैयार
5.0667371749878 क्वेरी
3.8260300159454 क्वेरी
4.0791549682617 क्वेरी
4.3775160312653 क्वेरी
3.6910600662231 क्वेरी
5.2708210945129 तैयार
6.2671611309052 तैयार
7.3791449069977 तैयार
(7) औसत तैयार: 6.0673267160143
(8) क्वेरी औसत: 4.3276024162769

मैं यह देखने के लिए उत्सुक हूं कि यह परीक्षण अन्य वातावरण में कैसे तुलना करता है, जैसे MySQL।


"अनुभवजन्य साक्ष्य" (या बल्कि कृत्रिम परीक्षण) के साथ समस्या यह है कि वे आपकी (अज्ञात) विशेष स्थितियों को दर्शाते हैं और किसी और के लिए अलग हो सकते हैं, अकेले वास्तविक दुनिया अनुभवजन्य साक्ष्य दें। फिर भी कुछ लोग इसे मान लेंगे और इस शब्द को और फैला देंगे।
आपका कॉमन सेंस

@YourCommonSense मैं पूरी तरह से सहमत हूँ, और आपकी प्रतिक्रिया के लिए धन्यवाद क्योंकि मुझे लगा कि यह मेरी साहसिक परिस्थितियों से स्पष्ट है। मुझे संदेह की एक स्वस्थ खुराक लगता है, लेकिन यह स्पष्ट नहीं है। कृपया मेरे उत्तर को संशोधित करके देखें, और मुझे बताएं कि इसे कैसे बेहतर बनाया जा सकता है।
जेफ पकेट
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.