2013-03-01 8 views
9

Sto cercando una tecnica SQL-injection-secure per inserire un sacco di righe (circa 2000) contemporaneamente con PHP e MySQLi.
Ho una matrice con tutti i valori che devono essere inclusi. Attualmente sto facendo che:Il modo migliore per INSERIRE molti valori in mysqli?

<?php 
$array = array("array", "with", "about", "2000", "values"); 

foreach ($array as $one) 
{ 
    $query = "INSERT INTO table (link) VALUES (?)"; 
    $stmt = $mysqli->prepare($query); 
    $stmt ->bind_param("s", $one); 
    $stmt->execute(); 
    $stmt->close(); 
} 
?> 

ho provato call_user_func_array(), ma ha causato uno StackOverflow.

Qual è il metodo più veloce per eseguire questa operazione (come inserirli tutti in una volta?), Ma ancora sicuro contro le iniezioni SQL (come un'istruzione preparata) e gli stackoverflow?
Grazie!

+0

1 preparare, N esecuzioni – zerkms

+1

Ma sarà davvero più veloce, se metto I loop sull'esecuzione? –

+0

cosa succede se ci provi? – zerkms

risposta

28

Dovresti essere in grado di aumentare notevolmente la velocità inserendo i tuoi inserti in una transazione. Puoi anche spostare le tue istruzioni di preparazione e rilegatura fuori dal tuo ciclo.

$array = array("array", "with", "about", "2000", "values"); 
$query = "INSERT INTO table (link) VALUES (?)"; 
$stmt = $mysqli->prepare($query); 
$stmt ->bind_param("s", $one); 

$mysqli->query("START TRANSACTION"); 
foreach ($array as $one) { 
    $stmt->execute(); 
} 
$stmt->close(); 
$mysqli->query("COMMIT"); 

Edit:

ho provato questo codice con 10.000 iterazioni sul mio server web.

Senza transazione: 226 seconds. con la transazione: 2 seconds. O un two order of magnitude speed increase, almeno per quel test.

+1

una magia: 'SET GLOBAL innodb_flush_log_at_trx_commit = 0;' quindi prova w/o transazione di nuovo ;-) –

+1

... o semplicemente usa MyISAM –

+0

@YourCommonSense Che riduce il tempo a 2 secondi senza una transazione, anche se basato sul documenti per quell'impostazione sembra che non dovrebbe essere identico alla velocità di una transazione, non è l'impostazione predefinita e potrebbe non essere super sicura. Sto leggendo quello sbagliato (o c'è un'altra domanda che va in questo?) –

6

Cercando di nuovo, non vedo il motivo per cui il codice originale non funzionerà con piccole modifiche:

$query = "INSERT INTO table (link) VALUES (?)"; 
$stmt = $mysqli->prepare($query); 
$stmt->bind_param("s", $one); 

foreach ($array as $one) { 
    $stmt->execute(); 
} 
$stmt->close(); 
+0

E non usare la dichiarazione preparata e inserire direttamente i valori nella query SQL, senza il binding e usando mysql_real_escape_string? –

+1

@Copy Devil: stai cercando di risolvere un compito reale o semplicemente cercando di pensare alla soluzione più strana? – zerkms

+0

Mi dispiace ^^ Sto solo pensando alla velocità di inserimento, se i valori vengono inseriti contemporaneamente rispetto a molte esecuzioni. –

2

Sì, si può costruire un unico grande richiesta manualmente, con qualcosa come:

$query = ""; 
foreach ($array as $curvalue) { 
    if ($query) 
    $query .= ","; 
    $query .= "('" . $mysqli->real_escape_string($curvalue) . "')"; 
} 
if ($query) { 
    $query = "INSERT INTO table (link) VALUES " . $query; 
    $mysqli->query($query); 
} 
+0

E quanto è vulnerabile real_escape_string? Ho sempre usato dichiarazioni preparate finora. –

+0

Le istruzioni preparate con le stringhe essenzialmente fanno esattamente la stessa cosa di real_escape_string. La differenza è che in genere è molto più codice e più facile da sbagliare con real_escape_string. –

+0

Allora? Sono un po 'confuso dai commenti delle risposte ora. Non sono sicuro di aver accettato la risposta giusta ^^ Quale delle due risposte è più veloce? E real_escape è davvero sicuro quanto le dichiarazioni preparate? –

Problemi correlati