पीडीओ ने एकल क्वेरी में कई पंक्तियों को तैयार किया


145

मैं वर्तमान में MySQL पर इस प्रकार के SQL का उपयोग एक एकल क्वेरी में मानों की कई पंक्तियों को सम्मिलित करने के लिए कर रहा हूँ:

INSERT INTO `tbl` (`key1`,`key2`) VALUES ('r1v1','r1v2'),('r2v1','r2v2'),...

पीडीओ पर रीडिंग पर, उपयोग किए गए तैयार किए गए स्टेटमेंट मुझे स्थिर प्रश्नों की तुलना में बेहतर सुरक्षा प्रदान करने चाहिए।

इसलिए मैं जानना चाहूंगा कि क्या तैयार कथनों का उपयोग करके "एक क्वेरी के उपयोग द्वारा मूल्यों की कई पंक्तियों को सम्मिलित करना" उत्पन्न करना संभव है।

यदि हाँ, तो क्या मुझे पता है कि मैं इसे कैसे लागू कर सकता हूं?


$stmt->execute($data); php.net/manual/en/… के लिए बहुत सारे उत्तरों के साथ सावधानी से मूल रूप से सभी पारम्स को स्ट्रिंग्स के रूप में मान्य किया गया है। क्वेरी बनाने, और मैन्युअल रूप से bindValueया bindParamतीसरे-तर्क के रूप में पास करने के बाद डेटा के माध्यम से लूप करें ।
MrMesees

जवाबों:


150

एकाधिक मान पीडीओ तैयार विवरण के साथ डालें

एक निष्पादित कथन में कई मान सम्मिलित करना। क्यों कि इस पृष्ठ के अनुसार यह नियमित आवेषण से तेज है।

$datafields = array('fielda', 'fieldb', ... );

$data[] = array('fielda' => 'value', 'fieldb' => 'value' ....);
$data[] = array('fielda' => 'value', 'fieldb' => 'value' ....);

अधिक डेटा मान या आपके पास संभवतः एक लूप है जो डेटा को पॉप्युलेट करता है।

तैयार आवेषण के साथ आपको उन फ़ील्ड्स को जानना होगा जिन्हें आप सम्मिलित कर रहे हैं, और फ़ील्ड बनाने की संख्या कितनी है? प्लेसहोल्डर्स अपने मापदंडों को बांधने के लिए।

insert into table (fielda, fieldb, ... ) values (?,?...), (?,?...)....

यह मूल रूप से है कि हम कैसे सम्मिलित विवरण चाहते हैं।

अब, कोड:

function placeholders($text, $count=0, $separator=","){
    $result = array();
    if($count > 0){
        for($x=0; $x<$count; $x++){
            $result[] = $text;
        }
    }

    return implode($separator, $result);
}

$pdo->beginTransaction(); // also helps speed up your inserts.
$insert_values = array();
foreach($data as $d){
    $question_marks[] = '('  . placeholders('?', sizeof($d)) . ')';
    $insert_values = array_merge($insert_values, array_values($d));
}

$sql = "INSERT INTO table (" . implode(",", $datafields ) . ") VALUES " .
       implode(',', $question_marks);

$stmt = $pdo->prepare ($sql);
try {
    $stmt->execute($insert_values);
} catch (PDOException $e){
    echo $e->getMessage();
}
$pdo->commit();

हालांकि मेरे परीक्षण में, एकल आवेषण के साथ कई आवेषण और नियमित रूप से तैयार आवेषण का उपयोग करते समय केवल 1 सेकंड का अंतर था।


4
एक टाइपो, इसके ऊपर की व्याख्या में $ डेटाफील्ड्स का उल्लेख है, हालांकि $ sql में $ डेटाफ़ील्ड का उपयोग किया जाता है। इस प्रकार कॉपी पेस्ट में त्रुटि होगी। कृपया सुधार करें। हालांकि इस समाधान के लिए धन्यवाद।
pal4life

1
थोड़ी देर के लिए इसका इस्तेमाल किया और फिर देखा कि उनमें एकल उद्धरण वाले मूल्य ठीक से बच नहीं पाए हैं। निहितार्थ पर दोहरे उद्धरण चिह्नों का उपयोग करना मेरे लिए एक आकर्षण की तरह काम करता है: $ a [] = '' (''। Implode (",", $ question_mark))। "", Now (()) ';
क्वाटर्ज़मैन

1
array_merge सिर्फ array_push का उपयोग करने से अधिक महंगा लगता है।
K2xL

14
जब आप कहते हैं कि "केवल 1 सेकंड का अंतर था", तो आप कितनी पंक्तियाँ डाल रहे थे? संदर्भ के आधार पर 1 सेकंड बहुत महत्वपूर्ण है।
केविन पासा

3
अनुकूलन: placeholders()बार-बार कॉल करने का कोई मतलब नहीं है । लूप के साथ एक बार पहले कॉल करें sizeof($datafields)और परिणाम स्ट्रिंग को $question_marks[]लूप के अंदर संलग्न करें ।
अविवाहित

71

श्री बालगृह के रूप में एक ही उत्तर, थोड़ा स्पष्ट ...

हाल के संस्करण MySQL और PHP पीडीओ कर समर्थन बहु पंक्ति INSERTबयान।

एसक्यूएल अवलोकन

एसक्यूएल कुछ इस तरह दिखेगा, एक 3-कॉलम तालिका जिसे आप करना चाहते हैं INSERT

INSERT INTO tbl_name
            (colA, colB, colC)
     VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?) [,...]

ON DUPLICATE KEY UPDATEबहु-पंक्ति INSERT के साथ भी अपेक्षित रूप से काम करता है; इसे जोड़ें:

ON DUPLICATE KEY UPDATE colA = VALUES(colA), colB = VALUES(colB), colC = VALUES(colC)

PHP अवलोकन

आपका PHP कोड सामान्य $pdo->prepare($qry)और $stmt->execute($params)PDO कॉल का अनुसरण करेगा ।

$paramsपास करने के लिए सभी मानों का 1-आयामी सरणी होगा INSERT

उपरोक्त उदाहरण में, इसमें 9 तत्व शामिल होने चाहिए; पीडीओ 3 के हर सेट का उपयोग मूल्यों की एक पंक्ति के रूप में करेगा। (3 स्तंभों की 3 पंक्तियों को प्रत्येक = 9 तत्व सरणी में सम्मिलित करना।)

कार्यान्वयन

नीचे कोड स्पष्टता के लिए लिखा गया है, दक्षता के लिए नहीं। array_*()यदि आप चाहें तो अपने डेटा के माध्यम से मैप या चलने के बेहतर तरीकों के लिए PHP के साथ काम करें। आप लेन-देन का उपयोग कर सकते हैं या नहीं यह स्पष्ट रूप से आपके MySQL तालिका प्रकार पर निर्भर करता है।

मान लिया जाये कि:

  • $tblName - INSERT को तालिका का स्ट्रिंग नाम
  • $colNames- तालिका के स्तंभ नामों का 1-आयामी सरणी ये स्तंभ नाम मान्य MySQL स्तंभ पहचानकर्ता होने चाहिए; अगर वे नहीं हैं तो उन्हें बैकटिक्स (``) के साथ छोड़ दें
  • $dataVals - परस्पर-आयामी सरणी, जहां प्रत्येक तत्व INSERT के लिए मूल्यों की एक पंक्ति का 1-d सरणी है

नमूना कोड

// setup data values for PDO
// memory warning: this is creating a copy all of $dataVals
$dataToInsert = array();

foreach ($dataVals as $row => $data) {
    foreach($data as $val) {
        $dataToInsert[] = $val;
    }
}

// (optional) setup the ON DUPLICATE column names
$updateCols = array();

foreach ($colNames as $curCol) {
    $updateCols[] = $curCol . " = VALUES($curCol)";
}

$onDup = implode(', ', $updateCols);

// setup the placeholders - a fancy way to make the long "(?, ?, ?)..." string
$rowPlaces = '(' . implode(', ', array_fill(0, count($colNames), '?')) . ')';
$allPlaces = implode(', ', array_fill(0, count($dataVals), $rowPlaces));

$sql = "INSERT INTO $tblName (" . implode(', ', $colNames) . 
    ") VALUES " . $allPlaces . " ON DUPLICATE KEY UPDATE $onDup";

// and then the PHP PDO boilerplate
$stmt = $pdo->prepare ($sql);

try {
   $stmt->execute($dataToInsert);
} catch (PDOException $e){
   echo $e->getMessage();
}

$pdo->commit();

6
यह वास्तव में बहुत बुरा है कि पीडीओ इसे इस तरह से संभालता है, अन्य डीबी ड्राइवरों में ऐसा करने के लिए कुछ बहुत ही सुरुचिपूर्ण तरीके हैं।
जोनाथन

यह प्लेसहोल्डर्स को और अधिक थकाऊ बनाता है, जो $rowPlacesअब आवश्यक नहीं है:$allPlaces = implode(',', array_fill(0, count($dataVals), '('.str_pad('', (count($colNames)*2)-1, '?,').')'));
फिल

सही काम करता है। मैं इस उत्तर को तालिका में अनुक्रमित () संयोजन की विशिष्टता सुनिश्चित करने की आवश्यकता से जोड़ूंगा। ALTER तालिका में रखना चाहते votesजोड़ें अद्वितीय unique_index( user, email, address);
Giuseppe

1
बहुत बढ़िया! BTW, का उपयोग array_push($dataToInsert, ...array_values($dataVals));करना बहुत तेज हो जाएगाforeach ($dataVals as $row => $data) {}
अनीस

39

इसके लायक क्या है, मैंने देखा है कि बहुत से उपयोगकर्ताओं ने एक एकल स्ट्रिंग क्वेरी के रूप में निर्माण करने के बजाय INSERT कथनों के माध्यम से पुनरावृत्ति करने की सिफारिश की, जैसा कि चयनित उत्तर ने किया था। मैंने सिर्फ दो क्षेत्रों और एक बहुत ही बुनियादी सम्मिलित विवरण के साथ एक साधारण परीक्षण चलाने का फैसला किया:

<?php
require('conn.php');

$fname = 'J';
$lname = 'M';

$time_start = microtime(true);
$stmt = $db->prepare('INSERT INTO table (FirstName, LastName) VALUES (:fname, :lname)');

for($i = 1; $i <= 10; $i++ )  {
    $stmt->bindParam(':fname', $fname);
    $stmt->bindParam(':lname', $lname);
    $stmt->execute();

    $fname .= 'O';
    $lname .= 'A';
}


$time_end = microtime(true);
$time = $time_end - $time_start;

echo "Completed in ". $time ." seconds <hr>";

$fname2 = 'J';
$lname2 = 'M';

$time_start2 = microtime(true);
$qry = 'INSERT INTO table (FirstName, LastName) VALUES ';
$qry .= "(?,?), ";
$qry .= "(?,?), ";
$qry .= "(?,?), ";
$qry .= "(?,?), ";
$qry .= "(?,?), ";
$qry .= "(?,?), ";
$qry .= "(?,?), ";
$qry .= "(?,?), ";
$qry .= "(?,?), ";
$qry .= "(?,?)";

$stmt2 = $db->prepare($qry);
$values = array();

for($j = 1; $j<=10; $j++) {
    $values2 = array($fname2, $lname2);
    $values = array_merge($values,$values2);

    $fname2 .= 'O';
    $lname2 .= 'A';
}

$stmt2->execute($values);

$time_end2 = microtime(true);
$time2 = $time_end2 - $time_start2;

echo "Completed in ". $time2 ." seconds <hr>";
?>

जबकि समग्र क्वेरी ने खुद को मिलीसेकंड या उससे कम लिया, बाद वाला (एकल स्ट्रिंग) क्वेरी लगातार 8 गुना अधिक या अधिक था। यदि यह कहने के लिए बनाया गया था कि कई और स्तंभों पर हजारों पंक्तियों के आयात को दर्शाया गया है, तो अंतर बहुत बड़ा हो सकता है।


@ JM4 - एक निष्पादन में सीधे 10 पंक्तियों को लगाने का महान विचार । लेकिन JSON जैसी ऑब्जेक्ट में संग्रहीत होने पर मैं हजारों पंक्तियों को कैसे सम्मिलित कर सकता हूं? नीचे दिया गया मेरा कोड काम करता है। लेकिन एक निष्पादन में 10 पंक्तियों को सम्मिलित करने के लिए मैं इसे कैसे समायोजित कर सकता हूं? `foreach ($ डेटा के रूप में $ json_content) {$ id = $ datarow [id]; $ तारीख = $ डेटारो [तिथि]; $ row3 = $ datarow [row3]; $ row4 = $ datarow [row4]; $ row5 = $ datarow [row5]; $ row6 = $ datarow [row6]; $ row7 = $ datarow [row7]; // अब $ databaseinsert-> execute () निष्पादित करें; } // फॉर्च्यूनर का अंत `
पीटर

@ JM4 - ... और मेरा दूसरा सवाल है: " bind_paramदूसरी आयात दिनचर्या में कोई बयान क्यों नहीं है"?
पीटर

क्या आपको दो बार लूप नहीं करना पड़ेगा? आपको डायनामिक रूप से (?,?)सही, सही उत्पन्न करना होगा?
नोबिशप्रो

@ नोबिशप्रो हाँ, आप दोनों को उत्पन्न करने के लिए / foreach के लिए समान का उपयोग कर सकते हैं।
चेज़ी चेज़

34

हर्बर्ट बालागटस द्वारा स्वीकृत उत्तर तब अच्छा काम करता है जब $ डेटा सरणी छोटा होता है। बड़े $ डेटा सरणियों के साथ array_merge फ़ंक्शन निषेधात्मक रूप से धीमा हो जाता है। $ डेटा सरणी बनाने के लिए मेरी परीक्षण फ़ाइल में 28 कॉल हैं और लगभग 80,000 लाइनें हैं। अंतिम स्क्रिप्ट को पूरा करने के लिए 41s लगे ।

Array_merge () के बजाय $ insert_values ​​बनाने के लिए array_push () का उपयोग करने के परिणामस्वरूप 0.41 के निष्पादन समय के साथ 100X की गति हुई ।

समस्याग्रस्त array_merge ():

$insert_values = array();

foreach($data as $d){
 $question_marks[] = '('  . placeholders('?', sizeof($d)) . ')';
 $insert_values = array_merge($insert_values, array_values($d));
}

Array_merge () की आवश्यकता को समाप्त करने के लिए, आप इसके बजाय निम्नलिखित दो सरणियों का निर्माण कर सकते हैं:

//Note that these fields are empty, but the field count should match the fields in $datafields.
$data[] = array('','','','',... n ); 

//getting rid of array_merge()
array_push($insert_values, $value1, $value2, $value3 ... n ); 

इन सरणियों को तब निम्नानुसार इस्तेमाल किया जा सकता है:

function placeholders($text, $count=0, $separator=","){
    $result = array();
    if($count > 0){
        for($x=0; $x<$count; $x++){
            $result[] = $text;
        }
    }

    return implode($separator, $result);
}

$pdo->beginTransaction();

foreach($data as $d){
 $question_marks[] = '('  . placeholders('?', sizeof($d)) . ')';
}

$sql = "INSERT INTO table (" . implode(",", array_keys($datafield) ) . ") VALUES " . implode(',', $question_marks);

$stmt = $pdo->prepare ($sql);
try {
    $stmt->execute($insert_values);
} catch (PDOException $e){
    echo $e->getMessage();
}
$pdo->commit();

4
PHP 5.6 में आप array_push($data, ...array_values($row))इसके बजाय कर सकते हैं $data = array_merge($data, array_values($row));। काफी तेज।
18

5.6 क्यों? दस्तावेज़ीकरण 5.6 के बारे में कुछ भी नहीं कहता है, array_push()यहां तक ​​कि php 4 में भी उपलब्ध है
ज़्यूरैबवेब

1
@Piero यह PHP 5.6+ केवल कोड का उपयोग करने के कारण नहीं है array_push(), लेकिन क्योंकि @Mark तर्क अनपैकिंग का उपयोग कर रहा है। ...array_values()वहाँ कॉल नोटिस ?
mariano.iglesias

@ mariano.iglesias array_values()php 4 में भी उपलब्ध है। यकीन नहीं होता तो इसका मतलब क्या है argument unpacking
ज़ुराबवेब

2
@Piero, Argument अनपैकिंग PHP 5.6 में एक विशेषता है। यह एक सरणी के रूप में कई तर्क प्रदान करने का एक तरीका है। यहां देखें - php.net/manual/en/…
Anis

14

दो संभावित दृष्टिकोण:

$stmt = $pdo->prepare('INSERT INTO foo VALUES(:v1_1, :v1_2, :v1_3),
    (:v2_1, :v2_2, :v2_3),
    (:v2_1, :v2_2, :v2_3)');
$stmt->bindValue(':v1_1', $data[0][0]);
$stmt->bindValue(':v1_2', $data[0][1]);
$stmt->bindValue(':v1_3', $data[0][2]);
// etc...
$stmt->execute();

या:

$stmt = $pdo->prepare('INSERT INTO foo VALUES(:a, :b, :c)');
foreach($data as $item)
{
    $stmt->bindValue(':a', $item[0]);
    $stmt->bindValue(':b', $item[1]);
    $stmt->bindValue(':c', $item[2]);
    $stmt->execute();
}

यदि सभी पंक्तियों का डेटा एक ही सरणी में है, तो मैं दूसरे समाधान का उपयोग करूंगा।


10
बाद में आप एक बयान में संयोजन के बजाय अलग-अलग निष्पादित कॉल के कई (संभवतः हजारों) बना रहे हैं?
JM4

@ JM4, क्या आप सुझाव दे रहे हैं $stmt->execute();कि फॉरेस्ट लूप के बाहर होना चाहिए?
बाफ्रोमका '

@ बेफ्रॉम्का - हां मैं हूं। ऊपर के साथ मेरा जवाब देखें। एक शुद्ध सम्मिलित विवरण पर कोई कारण नहीं है कि मैं तार्किक रूप से यह कह सकता हूं कि यह एक एकल कथन नहीं हो सकता है। एक कॉल, एक निष्पादित। वास्तव में, 2012 की शुरुआत से मेरे उत्तर को और भी बेहतर बनाया जा सकता था - कुछ ऐसा जो मैं बाद में करूंगा जब मेरे पास कुछ और समय होगा। यदि आप इन्सर्ट / अपडेट / डिलीट कॉम्बिनेशन में फेंकना शुरू करते हैं, तो यह एक अलग कहानी है।
JM4

12

यह केवल आपके द्वारा तैयार किए गए कथनों का उपयोग करने का तरीका नहीं है।

प्रति पंक्ति एक पंक्ति सम्मिलित करना पूरी तरह से ठीक है क्योंकि आप विभिन्न मापदंडों के साथ एक बार तैयार किए गए कथन को निष्पादित कर सकते हैं। वास्तव में यह एक सबसे बड़ा लाभ है क्योंकि यह आपको एक कुशल, सुरक्षित और आरामदायक तरीके से बड़ी संख्या में पंक्तियों को सम्मिलित करने की अनुमति देता है।

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


1
क्या आप एक तालिका में कई पंक्तियों को सम्मिलित करने का बेहतर तरीका सुझा सकते हैं?
क्रैशथच

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

2
तैयार कथन के लिए आपने जिस उद्देश्य का उल्लेख किया है वह सही है। लेकिन, इन्सर्ट स्पीड को बेहतर बनाने के लिए मल्टी -इन्टर का उपयोग करना दूसरी तकनीक है और इसे तैयार स्टेटमेंट के साथ भी इस्तेमाल किया जा सकता है। मेरे अनुभव में, पीडीओ तैयार स्टेटमेंट का उपयोग करते हुए 30 मिलियन पंक्ति डेटा को माइग्रेट करते समय, मैंने देखा कि मल्टी-इंसर्ट 7-10 गुना तेजी से था, फिर लेनदेन में एकल इंसर्ट किया।
आईस

1
अनीस के साथ बिल्कुल सहमत हैं। मेरे पास 100k पंक्तियाँ हैं और मुली पंक्ति आवेषण के साथ एक बड़ी गति वृद्धि प्राप्त करते हैं।
केनेथ

दावा है कि एक पंक्ति में एक संबंधपरक डेटाबेस को एक बार प्रति पंक्ति में कॉल करना आम तौर पर एक अच्छी बात है जिससे मैं सहमत नहीं हो सकता। उस के लिए नीचा दिखाना। दी, कभी-कभी यह ठीक है। मैं इंजीनियरिंग के साथ निरपेक्षता में विश्वास नहीं करता। लेकिन यह एक विरोधी पैटर्न है जिसका उपयोग केवल चुनिंदा मामलों में ही किया जाना चाहिए।
ब्रैंडन

8

एक छोटा उत्तर: कॉलम द्वारा आदेशित डेटा की सरणी को समतल करें

//$array = array( '1','2','3','4','5', '1','2','3','4','5');
$arCount = count($array);
$rCount = ($arCount  ? $arCount - 1 : 0);
$criteria = sprintf("(?,?,?,?,?)%s", str_repeat(",(?,?,?,?,?)", $rCount));
$sql = "INSERT INTO table(c1,c2,c3,c4,c5) VALUES$criteria";

1,000 या तो रिकॉर्ड सम्मिलित करते समय आप उन्हें दर्ज करने के लिए हर रिकॉर्ड के माध्यम से लूप नहीं करना चाहते हैं जब आपको ज़रूरत होती है तो मूल्यों की गिनती होती है।


5

यहाँ मेरा सरल तरीका है।

    $values = array();
    foreach($workouts_id as $value){
      $_value = "(".$value.",".$plan_id.")";
      array_push($values,$_value);
    }
    $values_ = implode(",",$values);

    $sql = "INSERT INTO plan_days(id,name) VALUES" . $values_."";
    $stmt = $this->conn->prepare($sql);
    $stmt->execute();

6
आप तैयार किए गए कथनों का उपयोग करने के बिंदु को हरा रहे हैं। op प्रश्न में सुरक्षा के बारे में चिंतित हैOn the readings on PDO, the use prepared statements should give me a better security than static queries.
YesItsMe

2
बस इमेजिंग कि आप गैर मान्य है $workouts_id, जो $valueकाफी अप्रत्याशित डेटा के साथ हो सकता है। आप गारंटी नहीं दे सकते कि शायद अब नहीं, लेकिन भविष्य में कोई अन्य डेवलपर इस डेटा को असुरक्षित बनाता है। इसलिए मुझे लगता है कि पीडीओ द्वारा तैयार की गई क्वेरी को और अधिक सही बनाते हैं।
निकिता_खारकोव_आयु

3

यहाँ मैंने एक वर्ग लिखा है जिसमें पर्स विकल्प के साथ कई आवेषण हैं:

<?php

/**
 * $pdo->beginTransaction();
 * $pmi = new PDOMultiLineInserter($pdo, "foo", array("a","b","c","e"), 10);
 * $pmi->insertRow($data);
 * ....
 * $pmi->insertRow($data);
 * $pmi->purgeRemainingInserts();
 * $pdo->commit();
 *
 */
class PDOMultiLineInserter {
    private $_purgeAtCount;
    private $_bigInsertQuery, $_singleInsertQuery;
    private $_currentlyInsertingRows  = array();
    private $_currentlyInsertingCount = 0;
    private $_numberOfFields;
    private $_error;
    private $_insertCount = 0;

    function __construct(\PDO $pdo, $tableName, $fieldsAsArray, $bigInsertCount = 100) {
        $this->_numberOfFields = count($fieldsAsArray);
        $insertIntoPortion = "INSERT INTO `$tableName` (`".implode("`,`", $fieldsAsArray)."`) VALUES";
        $questionMarks  = " (?".str_repeat(",?", $this->_numberOfFields - 1).")";

        $this->_purgeAtCount = $bigInsertCount;
        $this->_bigInsertQuery    = $pdo->prepare($insertIntoPortion.$questionMarks.str_repeat(", ".$questionMarks, $bigInsertCount - 1));
        $this->_singleInsertQuery = $pdo->prepare($insertIntoPortion.$questionMarks);
    }

    function insertRow($rowData) {
        // @todo Compare speed
        // $this->_currentlyInsertingRows = array_merge($this->_currentlyInsertingRows, $rowData);
        foreach($rowData as $v) array_push($this->_currentlyInsertingRows, $v);
        //
        if (++$this->_currentlyInsertingCount == $this->_purgeAtCount) {
            if ($this->_bigInsertQuery->execute($this->_currentlyInsertingRows) === FALSE) {
                $this->_error = "Failed to perform a multi-insert (after {$this->_insertCount} inserts), the following errors occurred:".implode('<br/>', $this->_bigInsertQuery->errorInfo());
                return false;
            }
            $this->_insertCount++;

            $this->_currentlyInsertingCount = 0;
            $this->_currentlyInsertingRows = array();
        }
        return true;
    }

    function purgeRemainingInserts() {
        while ($this->_currentlyInsertingCount > 0) {
            $singleInsertData = array();
            // @todo Compare speed - http://www.evardsson.com/blog/2010/02/05/comparing-php-array_shift-to-array_pop/
            // for ($i = 0; $i < $this->_numberOfFields; $i++) $singleInsertData[] = array_pop($this->_currentlyInsertingRows); array_reverse($singleInsertData);
            for ($i = 0; $i < $this->_numberOfFields; $i++) array_unshift($singleInsertData, array_pop($this->_currentlyInsertingRows));

            if ($this->_singleInsertQuery->execute($singleInsertData) === FALSE) {
                $this->_error = "Failed to perform a small-insert (whilst purging the remaining rows; the following errors occurred:".implode('<br/>', $this->_singleInsertQuery->errorInfo());
                return false;
            }
            $this->_currentlyInsertingCount--;
        }
    }

    public function getError() {
        return $this->_error;
    }
}

हैलो पियरे। हो सकता है कि आप अब यहां सक्रिय नहीं हैं। फिर भी, मैं सिर्फ यह बताना चाहता था कि इस मुद्दे के लिए मेरा विचार आपके लिए लगभग समान है। शुद्ध संयोग, जैसा कि मुझे लगता है कि यह बहुत अधिक नहीं है। मैंने DELETE- और UPDATE- संचालन के लिए कक्षाएं भी जोड़ीं और यहां से कुछ विचार भी शामिल किए, बाद में। मैंने अभी आपकी कक्षा नहीं देखी। कृपया यहाँ मेरे बेशर्म आत्म प्रचार को बढ़ावा दें, लेकिन मुझे लगता है कि यह किसी के लिए मदद का होगा। आशा है कि यह SO-नियमों के विरुद्ध नहीं है। इसे यहाँ खोजें ।
जैकलेमरमेरदेउर

1

मैंने इस तरह से इसे किया:

पहले आपके द्वारा उपयोग किए जाने वाले कॉलम नामों को परिभाषित करें, या इसे खाली छोड़ दें और pdo मान लेगा कि आप तालिका के सभी कॉलमों का उपयोग करना चाहते हैं - जिस स्थिति में आपको तालिका में दिखाई देने वाले सटीक क्रम में पंक्ति मानों को सूचित करना होगा। ।

$cols = 'name', 'middleName', 'eMail';
$table = 'people';

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

foreach ( $people as $person ) {
if(! $rowVals ) {
$rows = '(' . "'$name'" . ',' . "'$middleName'" . ',' .           "'$eMail'" . ')';
} else { $rowVals  = '(' . "'$name'" . ',' . "'$middleName'" . ',' . "'$eMail'" . ')';
}

अब, आपने अभी क्या किया था अगर जाँच करें कि $ पंक्तियों को पहले से ही परिभाषित किया गया था, और यदि नहीं, तो इसे बनाएं और पंक्ति मानों और आवश्यक SQL सिंटैक्स को संग्रहीत करें ताकि यह एक मान्य कथन हो। ध्यान दें कि तार डबल कोट्स और सिंगल कोट्स के अंदर जाने चाहिए, इसलिए उन्हें तुरंत इस तरह से पहचाना जाएगा।

यह सब करना बाकी है, इस तरह से कथन तैयार करना और निष्पादित करना है:

$stmt = $db->prepare ( "INSERT INTO $table $cols VALUES $rowVals" );
$stmt->execute ();

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

सादर।


1

चूंकि यह अभी तक सुझाया नहीं गया है, मुझे पूरा यकीन है कि LOAD DATA INFILE अभी भी डेटा लोड करने का सबसे तेज़ तरीका है क्योंकि यह अनुक्रमण को निष्क्रिय करता है, सभी डेटा सम्मिलित करता है, और फिर अनुक्रमणिका को सक्षम करता है - सभी एक ही अनुरोध में।

डेटा को csv के रूप में सहेजना fputcsv को ध्यान में रखते हुए काफी तुच्छ होना चाहिए। MyISAM सबसे तेज़ है, लेकिन आपको अभी भी InnoDB में बड़ा प्रदर्शन मिलता है। अन्य नुकसान भी हैं, हालांकि यदि आप बहुत अधिक डेटा डाल रहे हैं, तो मैं इस मार्ग पर जाऊंगा, और 100 पंक्तियों के साथ परेशान नहीं करूंगा।


1

हालाँकि एक पुराने प्रश्न ने सभी योगदानों ने मुझे यहाँ बहुत हल करने में मदद की, जो मेरी अपनी DbContextकक्षा के भीतर काम करता है । $rowsपैरामीटर बस पंक्तियों या मॉडल का प्रतिनिधित्व करने साहचर्य सरणियों की एक सरणी है: field name => insert value

यदि आप किसी ऐसे पैटर्न का उपयोग करते हैं, जो मॉडल डेटा का उपयोग करता है, तो एक मॉडल के रूप में एक सरणी के रूप में पास ToRowArrayहोने पर, मॉडल वर्ग के भीतर एक विधि से कहता है ।

नोट : इसे बिना कहे जाना चाहिए, लेकिन कभी भी इस पद्धति को पारित किए गए तर्कों को उपयोगकर्ता के सामने या किसी उपयोगकर्ता इनपुट पर निर्भर न होने दें, इनसर्ट वैल्यू के अलावा, जो मान्य और स्वीकृत किए गए हैं। $tableNameतर्क और स्तंभ नाम बुला तर्क के आधार पर परिभाषित किया जाना चाहिए; उदाहरण के लिए, एक Userमॉडल को उपयोगकर्ता तालिका में मैप किया जा सकता है, जिसकी कॉलम सूची मॉडल के सदस्य क्षेत्रों में मैप की गई है।

public function InsertRange($tableName, $rows)
{
    // Get column list
    $columnList = array_keys($rows[0]);
    $numColumns = count($columnList);
    $columnListString = implode(",", $columnList);

    // Generate pdo param placeholders
    $placeHolders = array();

    foreach($rows as $row)
    {
        $temp = array();

        for($i = 0; $i < count($row); $i++)
            $temp[] = "?";

        $placeHolders[] = "(" . implode(",", $temp) . ")";
    }

    $placeHolders = implode(",", $placeHolders);

    // Construct the query
    $sql = "insert into $tableName ($columnListString) values $placeHolders";
    $stmt = $this->pdo->prepare($sql);

    $j = 1;
    foreach($rows as $row)
    {
        for($i = 0; $i < $numColumns; $i++)
        {
            $stmt->bindParam($j, $row[$columnList[$i]]);
            $j++;
        }
    }

    $stmt->execute();
}

लेन-देन से छुटकारा पाएं, क्योंकि यह एक क्वेरी के लिए एक का उपयोग करने के लिए कोई मतलब नहीं है। और हमेशा की तरह, यह कोड SQL इंजेक्शन या क्वेरी त्रुटि के लिए असुरक्षित है।
आपका कॉमन सेंस

आप इस मामले के लिए लेन-देन के निरर्थक उपयोग के बारे में सही हैं, लेकिन मैं यह नहीं देखता कि यह SQL इंजेक्शन के लिए कैसे असुरक्षित है। यह मानकीकृत है इसलिए मैं केवल यह मान सकता हूं कि आप मान रहे हैं कि $tableNameउपयोगकर्ता के संपर्क में है, जो यह नहीं है, यह डीएएल में है। क्या आप अपने दावों पर विस्तार कर सकते हैं? यह सिर्फ बातें कहने के लिए उपयोगी नहीं है।
ली

ठीक है, यह न केवल एक टेबल का नाम है, बल्कि वैसे भी: आप यह कैसे जान सकते हैं कि यह आपके द्वारा पोस्ट किए गए कोड का उपयोग करने वाले किसी व्यक्ति
आपका कॉमन सेंस

तो यह एक पोस्टर की जिम्मेदारी है कि वह कोड के हर संभावित उपयोग या तर्कों के लिए हर स्रोत की रूपरेखा तैयार करे? शायद मुझे लोगों की अपेक्षाएँ अधिक हैं। अगर मैंने एक नोट जोड़ दिया तो क्या आप इसे और अधिक खुश कर पाएंगे $tableName?
ली

यह एक विश्वसनीय कोड पोस्ट करने के लिए पोस्टर की जिम्मेदारी है, अगर उनका इरादा किसी की मदद करना है, न कि केवल दिखावा करना।
आपका कॉमन सेंस

1

इस मुद्दे का दूसरा (पतला) समाधान यहां दिया गया है:

सबसे पहले आपको स्रोत सरणी (यहां: $ aData) का डेटा काउंट () के साथ गिनना होगा। तब आप array_fill () का उपयोग करते हैं और एक नई एरे विच उत्पन्न करते हैं, जैसा कि स्रोत एरे के रूप में कई प्रविष्टियां हैं, प्रत्येक का मान "(?)?" (प्लेसहोल्डर्स की संख्या आपके द्वारा उपयोग किए जाने वाले फ़ील्ड पर निर्भर करती है; यहां: 2)। फिर उत्पन्न सरणी को फंसाया जाना चाहिए और चूंकि गोंद अल्पविराम का उपयोग किया जाता है। फ़ॉरेस्ट लूप के भीतर, आपको अपने द्वारा उपयोग किए जाने वाले प्लेसहोल्डर्स की संख्या (प्लेसहोल्डर्स की संख्या * वर्तमान एरे इंडेक्स +) के संबंध में एक और सूचकांक उत्पन्न करने की आवश्यकता है। आपको प्रत्येक बाइंड किए गए मान के बाद उत्पन्न इंडेक्स में 1 जोड़ना होगा।

$do = $db->prepare("INSERT INTO table (id, name) VALUES ".implode(',', array_fill(0, count($aData), '(?,?)')));

foreach($aData as $iIndex => $aValues){
 $iRealIndex = 2 * $iIndex + 1;
 $do->bindValue($iRealIndex, $aValues['id'], PDO::PARAM_INT);
 $iRealIndex = $iRealIndex + 1;
 $do->bindValue($iRealIndex, $aValues['name'], PDO::PARAM_STR);
}

$do->execute();

0

आप इस फ़ंक्शन के साथ एक ही क्वेरी में कई पंक्तियाँ सम्मिलित कर सकते हैं:

function insertMultiple($query,$rows) {
    if (count($rows)>0) {
        $args = array_fill(0, count($rows[0]), '?');

        $params = array();
        foreach($rows as $row)
        {
            $values[] = "(".implode(',', $args).")";
            foreach($row as $value)
            {
                $params[] = $value;
            }
        }

        $query = $query." VALUES ".implode(',', $values);
        $stmt = $PDO->prepare($query);
        $stmt->execute($params);
    }
}

$ पंक्ति मूल्यों की सरणियों का एक सरणी है। आपके मामले में आप फ़ंक्शन को कॉल करेंगे

insertMultiple("INSERT INTO tbl (`key1`,`key2`)",array(array('r1v1','r1v2'),array('r2v1','r2v2')));

इसका एक लाभ है कि आप तैयार कथनों का उपयोग करते हैं, जबकि एक ही क्वेरी के साथ कई पंक्तियाँ सम्मिलित करते हैं। सुरक्षा!


0

यहाँ मेरा समाधान है: https://github.com/sasha-ch/Aura.Sql auraphp / Aura.Sql लाइब्रेरी पर आधारित।

उपयोग उदाहरण:

$q = "insert into t2(id,name) values (?,?), ... on duplicate key update name=name"; 
$bind_values = [ [[1,'str1'],[2,'str2']] ];
$pdo->perform($q, $bind_values);

Bugreports का स्वागत है।


2.4 के रूप में आप github.com/auraphp/Aura.SqlQuery/tree/… के साथ मल्टी इंसर्ट बना सकते हैं और :) निष्पादित करने के लिए ExtendedPdo का उपयोग कर सकते हैं ।
हरि केटी

0

एक खाली तालिका में सभी जर्मन पोस्टकोड सम्मिलित करने के लिए मेरा वास्तविक विश्व उदाहरण (बाद में शहर के नाम जोड़ने के लिए):

// obtain column template
$stmt = $db->prepare('SHOW COLUMNS FROM towns');
$stmt->execute();
$columns = array_fill_keys(array_values($stmt->fetchAll(PDO::FETCH_COLUMN)), null);
// multiple INSERT
$postcode = '01000';// smallest german postcode
while ($postcode <= 99999) {// highest german postcode
    $values = array();
    while ($postcode <= 99999) {
        // reset row
        $row = $columns;
        // now fill our row with data
        $row['postcode'] = sprintf('%05d', $postcode);
        // build INSERT array
        foreach ($row as $value) {
            $values[] = $value;
        }
        $postcode++;
        // avoid memory kill
        if (!($postcode % 10000)) {
            break;
        }
    }
    // build query
    $count_columns = count($columns);
    $placeholder = ',(' . substr(str_repeat(',?', $count_columns), 1) . ')';//,(?,?,?)
    $placeholder_group = substr(str_repeat($placeholder, count($values) / $count_columns), 1);//(?,?,?),(?,?,?)...
    $into_columns = implode(',', array_keys($columns));//col1,col2,col3
    // this part is optional:
    $on_duplicate = array();
    foreach ($columns as $column => $row) {
        $on_duplicate[] = $column;
        $on_duplicate[] = $column;
    }
    $on_duplicate = ' ON DUPLICATE KEY UPDATE' . vsprintf(substr(str_repeat(', %s = VALUES(%s)', $count_columns), 1), $on_duplicate);
    // execute query
    $stmt = $db->prepare('INSERT INTO towns (' . $into_columns . ') VALUES' . $placeholder_group . $on_duplicate);//INSERT INTO towns (col1,col2,col3) VALUES(?,?,?),(?,?,?)... {ON DUPLICATE...}
    $stmt->execute($values);
}

जैसा कि आप इसकी पूरी तरह से लचीला देख सकते हैं। आपको कॉलम की मात्रा की जाँच करने या यह जाँचने की आवश्यकता नहीं है कि आपका कॉलम किस स्थिति में है। आपको केवल सम्मिलित डेटा सेट करने की आवश्यकता है:

    $row['postcode'] = sprintf('%05d', $postcode);

मुझे कुछ क्वेरी स्ट्रिंग कंस्ट्रक्टर पर गर्व है क्योंकि वे array_merge जैसे भारी सरणी-फंक्शन के बिना काम करते हैं। विशेष रूप से vsprintf () एक अच्छा खोज था।

अंत में मुझे मेमोरी सीमा से अधिक बचने के लिए 2x () जोड़ने की आवश्यकता थी। यह आपकी मेमोरी सीमा पर निर्भर करता है लेकिन समस्याओं से बचने के लिए एक अच्छा सामान्य समाधान है (और 10 प्रश्न होने के बाद भी 10.000 से बहुत बेहतर है)।


0

test.php

<?php
require_once('Database.php');

$obj = new Database();
$table = "test";

$rows = array(
    array(
    'name' => 'balasubramani',
    'status' => 1
    ),
    array(
    'name' => 'balakumar',
    'status' => 1
    ),
    array(
    'name' => 'mani',
    'status' => 1
    )
);

var_dump($obj->insertMultiple($table,$rows));
?>

database.php

<?php
class Database 
{

    /* Initializing Database Information */

    var $host = 'localhost';
    var $user = 'root';
    var $pass = '';
    var $database = "database";
    var $dbh;

    /* Connecting Datbase */

    public function __construct(){
        try {
            $this->dbh = new PDO('mysql:host='.$this->host.';dbname='.$this->database.'', $this->user, $this->pass);
            //print "Connected Successfully";
        } 
        catch (PDOException $e) {
            print "Error!: " . $e->getMessage() . "<br/>";
            die();
        }
    }
/* Insert Multiple Rows in a table */

    public function insertMultiple($table,$rows){

        $this->dbh->beginTransaction(); // also helps speed up your inserts.
        $insert_values = array();
        foreach($rows as $d){
            $question_marks[] = '('  . $this->placeholders('?', sizeof($d)) . ')';
            $insert_values = array_merge($insert_values, array_values($d));
            $datafields = array_keys($d);
        }

        $sql = "INSERT INTO $table (" . implode(",", $datafields ) . ") VALUES " . implode(',', $question_marks);

        $stmt = $this->dbh->prepare ($sql);
        try {
            $stmt->execute($insert_values);
        } catch (PDOException $e){
            echo $e->getMessage();
        }
        return $this->dbh->commit();
    }

    /*  placeholders for prepared statements like (?,?,?)  */

    function placeholders($text, $count=0, $separator=","){
        $result = array();
        if($count > 0){
            for($x=0; $x<$count; $x++){
                $result[] = $text;
            }
        }

        return implode($separator, $result);
    }

}
?>

Stackoverflow में आपका स्वागत है। सिर्फ कोड ही नहीं, कृपया अपनी समस्या बताएं और समझाएं।
प्रकाश पालनाति

मूल रूप से। यह स्वीकार किए गए उत्तर में प्रदान किए गए कोड का सिर्फ एक कार्यान्वयन है
आपका कॉमन सेंस

0

मुझे भी यही समस्या थी और इसी तरह मैंने अपने लिए काम पूरा किया और मैंने इसके लिए अपने लिए एक फंक्शन बनाया (और अगर आप इसमें मदद करते हैं तो आप इसका इस्तेमाल कर सकते हैं)।

उदाहरण:

INSERT INTO देशों (देश, शहर) VALUES (जर्मनी, बर्लिन), (फ्रांस, पेरिस);

$arr1 = Array("Germany", "Berlin");
$arr2 = Array("France", "France");

insertMultipleData("countries", Array($arr1, $arr2));


// Inserting multiple data to the Database.
public function insertMultipleData($table, $multi_params){
    try{
        $db = $this->connect();

        $beforeParams = "";
        $paramsStr = "";
        $valuesStr = "";

        for ($i=0; $i < count($multi_params); $i++) { 

            foreach ($multi_params[$i] as $j => $value) {                   

                if ($i == 0) {
                    $beforeParams .=  " " . $j . ",";
                }

                $paramsStr .= " :"  . $j . "_" . $i .",";                                       
            }

            $paramsStr = substr_replace($paramsStr, "", -1);
            $valuesStr .=  "(" . $paramsStr . "),"; 
            $paramsStr = "";
        }


        $beforeParams = substr_replace($beforeParams, "", -1);
        $valuesStr = substr_replace($valuesStr, "", -1);


        $sql = "INSERT INTO " . $table . " (" . $beforeParams . ") VALUES " . $valuesStr . ";";

        $stmt = $db->prepare($sql);


        for ($i=0; $i < count($multi_params); $i++) { 
            foreach ($multi_params[$i] as $j => &$value) {
                $stmt->bindParam(":" . $j . "_" . $i, $value);                                      
            }
        }

        $this->close($db);
        $stmt->execute();                       

        return true;

    }catch(PDOException $e){            
        return false;
    }

    return false;
}

// Making connection to the Database 
    public function connect(){
        $host = Constants::DB_HOST;
        $dbname = Constants::DB_NAME;
        $user = Constants::DB_USER;
        $pass = Constants::DB_PASS;

        $mysql_connect_str = 'mysql:host='. $host . ';dbname=' .$dbname;

        $dbConnection = new PDO($mysql_connect_str, $user, $pass);
        $dbConnection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

        return $dbConnection;
    }

    // Closing the connection
    public function close($db){
        $db = null;
    }

यदि InsertMultipleData ($ table, $ multi_params) TRUE लौटाता है , तो आपका डेटा आपके डेटाबेस में डाला गया है।


0

मेरे प्रयोगों के आधार पर मुझे पता चला कि एकल लेनदेन में कई मूल्य पंक्तियों के साथ mysql सम्मिलित विवरण सबसे तेज़ है।

हालाँकि, यदि डेटा बहुत अधिक है तो mysql की max_allowed_packetसेटिंग एकल लेन-देन सम्मिलित को कई मूल्य पंक्तियों के साथ प्रतिबंधित कर सकती है। इसलिए, mysql के max_allowed_packetआकार से अधिक डेटा होने पर निम्नलिखित कार्य विफल हो जाएंगे :

  1. singleTransactionInsertWithRollback
  2. singleTransactionInsertWithPlaceholders
  3. singleTransactionInsert

विशाल डेटा परिदृश्य सम्मिलित करने में सबसे सफल एक transactionSpeedविधि है, लेकिन यह उपर्युक्त तरीकों से अधिक समय लेता है। इसलिए, इस समस्या से निपटने के लिए आप या तो अपने डेटा को छोटे-छोटे हिस्सों में विभाजित कर सकते हैं और एकल लेनदेन को कई बार सम्मिलित कर सकते हैं या उपयोग करके निष्पादन की गति छोड़ सकते हैंtransactionSpeed विधि ।

यहाँ मेरा शोध है

<?php

class SpeedTestClass
{
    private $data;

    private $pdo;

    public function __construct()
    {
        $this->data = [];
        $this->pdo = new \PDO('mysql:dbname=test_data', 'admin', 'admin');
        if (!$this->pdo) {
            die('Failed to connect to database');
        }
    }

    public function createData()
    {
        $prefix = 'test';
        $postfix = 'unicourt.com';
        $salutations = ['Mr.', 'Ms.', 'Dr.', 'Mrs.'];

        $csv[] = ['Salutation', 'First Name', 'Last Name', 'Email Address'];
        for ($i = 0; $i < 100000; ++$i) {
            $csv[] = [
                $salutations[$i % \count($salutations)],
                $prefix.$i,
                $prefix.$i,
                $prefix.$i.'@'.$postfix,
            ];
        }

        $this->data = $csv;
    }

    public function truncateTable()
    {
        $this->pdo->query('TRUNCATE TABLE `name`');
    }

    public function transactionSpeed()
    {
        $timer1 = microtime(true);
        $this->pdo->beginTransaction();
        $sql = 'INSERT INTO `name` (`first_name`, `last_name`) VALUES (:first_name, :last_name)';
        $sth = $this->pdo->prepare($sql);

        foreach (\array_slice($this->data, 1) as $values) {
            $sth->execute([
                ':first_name' => $values[1],
                ':last_name' => $values[2],
            ]);
        }

        // $timer2 = microtime(true);
        // echo 'Prepare Time: '.($timer2 - $timer1).PHP_EOL;
        // $timer3 = microtime(true);

        if (!$this->pdo->commit()) {
            echo "Commit failed\n";
        }
        $timer4 = microtime(true);
        // echo 'Commit Time: '.($timer4 - $timer3).PHP_EOL;

        return $timer4 - $timer1;
    }

    public function autoCommitSpeed()
    {
        $timer1 = microtime(true);
        $sql = 'INSERT INTO `name` (`first_name`, `last_name`) VALUES (:first_name, :last_name)';
        $sth = $this->pdo->prepare($sql);
        foreach (\array_slice($this->data, 1) as $values) {
            $sth->execute([
                ':first_name' => $values[1],
                ':last_name' => $values[2],
            ]);
        }
        $timer2 = microtime(true);

        return $timer2 - $timer1;
    }

    public function noBindAutoCommitSpeed()
    {
        $timer1 = microtime(true);

        foreach (\array_slice($this->data, 1) as $values) {
            $sth = $this->pdo->prepare("INSERT INTO `name` (`first_name`, `last_name`) VALUES ('{$values[1]}', '{$values[2]}')");
            $sth->execute();
        }
        $timer2 = microtime(true);

        return $timer2 - $timer1;
    }

    public function singleTransactionInsert()
    {
        $timer1 = microtime(true);
        foreach (\array_slice($this->data, 1) as $values) {
            $arr[] = "('{$values[1]}', '{$values[2]}')";
        }
        $sth = $this->pdo->prepare('INSERT INTO `name` (`first_name`, `last_name`) VALUES '.implode(', ', $arr));
        $sth->execute();
        $timer2 = microtime(true);

        return $timer2 - $timer1;
    }

    public function singleTransactionInsertWithPlaceholders()
    {
        $placeholders = [];
        $timer1 = microtime(true);
        $sql = 'INSERT INTO `name` (`first_name`, `last_name`) VALUES ';
        foreach (\array_slice($this->data, 1) as $values) {
            $placeholders[] = '(?, ?)';
            $arr[] = $values[1];
            $arr[] = $values[2];
        }
        $sql .= implode(', ', $placeholders);
        $sth = $this->pdo->prepare($sql);
        $sth->execute($arr);
        $timer2 = microtime(true);

        return $timer2 - $timer1;
    }

    public function singleTransactionInsertWithRollback()
    {
        $placeholders = [];
        $timer1 = microtime(true);
        $sql = 'INSERT INTO `name` (`first_name`, `last_name`) VALUES ';
        foreach (\array_slice($this->data, 1) as $values) {
            $placeholders[] = '(?, ?)';
            $arr[] = $values[1];
            $arr[] = $values[2];
        }
        $sql .= implode(', ', $placeholders);
        $this->pdo->beginTransaction();
        $sth = $this->pdo->prepare($sql);
        $sth->execute($arr);
        $this->pdo->commit();
        $timer2 = microtime(true);

        return $timer2 - $timer1;
    }
}

$s = new SpeedTestClass();
$s->createData();
$s->truncateTable();
echo "Time Spent for singleTransactionInsertWithRollback: {$s->singleTransactionInsertWithRollback()}".PHP_EOL;
$s->truncateTable();
echo "Time Spent for single Transaction Insert: {$s->singleTransactionInsert()}".PHP_EOL;
$s->truncateTable();
echo "Time Spent for single Transaction Insert With Placeholders: {$s->singleTransactionInsertWithPlaceholders()}".PHP_EOL;
$s->truncateTable();
echo "Time Spent for transaction: {$s->transactionSpeed()}".PHP_EOL;
$s->truncateTable();
echo "Time Spent for AutoCommit: {$s->noBindAutoCommitSpeed()}".PHP_EOL;
$s->truncateTable();
echo "Time Spent for autocommit with bind: {$s->autoCommitSpeed()}".PHP_EOL;
$s->truncateTable();

केवल दो कॉलम वाली तालिका के लिए 100,000 प्रविष्टियों के परिणाम नीचे दिए गए हैं

$ php data.php
Time Spent for singleTransactionInsertWithRollback: 0.75147604942322
Time Spent for single Transaction Insert: 0.67445182800293
Time Spent for single Transaction Insert With Placeholders: 0.71131205558777
Time Spent for transaction: 8.0056409835815
Time Spent for AutoCommit: 35.4979159832
Time Spent for autocommit with bind: 33.303519010544

0

इसने मेरे लिए काम किया

$sql = 'INSERT INTO table(pk_pk1,pk_pk2,date,pk_3) VALUES '; 
$qPart = array_fill(0, count($array), "(?, ?,UTC_TIMESTAMP(),?)");
$sql .= implode(",", $qPart);
$stmt =    DB::prepare('base', $sql);
$i = 1;
foreach ($array as $value) { 
  $stmt->bindValue($i++, $value);
  $stmt->bindValue($i++, $pk_pk1);
  $stmt->bindValue($i++, $pk_pk2); 
  $stmt->bindValue($i++, $pk_pk3); 
} 
$stmt->execute();

0

इस तरह के किसी चीज़ के बारे में क्या:

        if(count($types_of_values)>0){
         $uid = 1;
         $x = 0;
         $sql = "";
         $values = array();
          foreach($types_of_values as $k=>$v){
            $sql .= "(:id_$k,:kind_of_val_$k), ";
            $values[":id_$k"] = $uid;
            $values[":kind_of_val_$k"] = $v;
          }
         $sql = substr($sql,0,-2);
         $query = "INSERT INTO table (id,value_type) VALUES $sql";
         $res = $this->db->prepare($query);
         $res->execute($values);            
        }

इसके पीछे का विचार आपके सरणी मूल्यों के माध्यम से चक्र करना है, अपने तैयार किए गए स्टेटमेंट प्लेसहोल्डर्स के लिए प्रत्येक लूप में "आईडी नंबर" जोड़ते हुए, साथ ही साथ आप बाइंडिंग मापदंडों के लिए अपने एरे को मान जोड़ते हैं। यदि आपको सरणी से "कुंजी" सूचकांक का उपयोग करना पसंद नहीं है, तो आप लूप के अंदर $ i = 0, और $ i ++ जोड़ सकते हैं। या तो इस उदाहरण में काम करता है, भले ही आपके पास नामांकित कुंजी के साथ साहचर्य सरणियां हों, यह तब भी काम करेगा जब कुंजियां अद्वितीय थीं। थोड़े काम के साथ यह नेस्टेड सरणियों के लिए भी ठीक होगा।

** ध्यान दें कि अगर आप एक जगह नहीं रखते हैं, तो आपके पास $ sql वैरिएबल का अंतिम स्थान और अल्पविराम है, तो आपको -2 के बजाय इसे -1 में बदलना होगा।


-1

तैयार क्वेरी बनाने के लिए यहां दिए गए अधिकांश समाधान अधिक जटिल हैं जो उन्हें होने की आवश्यकता है। PHP के फंक्शंस का उपयोग करके आप महत्वपूर्ण ओवरहेड के बिना आसानी से SQL स्टेटमेंट को क्रेज कर सकते हैं।

यह देखते हुए $records, अभिलेखों का एक सरणी जहां प्रत्येक रिकॉर्ड अपने आप में एक अनुक्रमित सरणी (के रूप में field => value) है, निम्न फ़ंक्शन दिए गए तालिका में रिकॉर्ड्स को $tableपीडीओ कनेक्शन पर $connectionकेवल एक ही तैयार विवरण का उपयोग करके सम्मिलित करेगा । ध्यान दें कि कॉल में तर्क अनपैकिंग के उपयोग के कारण यह PHP 5.6+ समाधान है array_push:

private function import(PDO $connection, $table, array $records)
{
    $fields = array_keys($records[0]);
    $placeHolders = substr(str_repeat(',?', count($fields)), 1);
    $values = [];
    foreach ($records as $record) {
        array_push($values, ...array_values($record));
    }

    $query = 'INSERT INTO ' . $table . ' (';
    $query .= implode(',', $fields);
    $query .= ') VALUES (';
    $query .= implode('),(', array_fill(0, count($records), $placeHolders));
    $query .= ')';

    $statement = $connection->prepare($query);
    $statement->execute($values);
}

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