PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PHP -> PDO -> Prepared-Statements -> mehrere INSERT-Befehle


dav133
2009-07-04, 16:31:23
Hallo,

folgendes Problem:

Ich muss zum befuellen einer Datenbank INSERT-Befehle aus einer Schleife heraus ausführen. Mal auf ein simples Beispiel runtergebrochen, sieht das so aus (es wird PDO mit perpared statements verwendet):


$statement = $db->prepare( "INSERT INTO tabelle (`wert`) VALUES (:wert )" );
for ($i=0;$i<=$max;$i++)
{
$statement->bindParam( ":wert", $i, PDO::PARAM_INT );
$statement->execute();
}


Nun ist ja bekannt, dass SQL-Befehle in Loops nicht besonders performant sind. Mit "normalem" SQL haette ich mir erstmal einen SQL-String generiert, etwa folgendermaßen:


$sqlBefehl="INSERT INTO tabelle (wert) VALUES ";
for ($i=0;$i<=$max;$i++)
{
$sqlBefehl.='('.$i.'),';
}
mysql_query($sqlBefehl);
//ergibt:
//INSERT INTO tabelle (wert) VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9),(10) ....
// (das letzte Komma müsste logischerweise noch abgeschnitten werden)


So würde ich die Datenbank nur einmal ansprechen müssen. Mit prepared Statements ist sowas allerdings nicht zu machen. Jetzt hab ich mich in die "transations" bei PDO eingelesen, allerdings funktioniert das auch nicht so wie gedacht, die Datenbank wird nämlich trotzdem bei jedem Schleifendurchlauf angesteuert und nicht nur einmal am Ende bei "commit", wie ich mir das vorgestellt hätte.


$db->beginTransaction();

$statement = $db->prepare( "INSERT INTO tabelle (`wert`) VALUES (:wert )");
for ($i=0;$i<=$max;$i++)
{
$statement->bindParam( ":wert", $i, PDO::PARAM_INT );
$statement->execute();
}

$db->commit();


/edit: Grad gelesen, dass beginTransaction() anscheinend mit der von mir verwendeten Storageengine myisam garnicht funktioniert :(


Abhilfe ;)?

lg

samm
2009-07-04, 17:17:54
Wirklich schön ist es ja auch nicht, hab jetzt nicht besonders weit gedacht, aber du könntest den prepare-String auch dynamisch erzeugen, und so viele Platzhalter "?" wie Werte einfügen. Dann bindest du die Werte in einer Schleife und executest nur einmal nach der Schleife. Scheint mir aber ehrlich gesagt keinen Vorteil zu haben gegenüber der dynamischen SQL-Erzeugung.

robobimbo
2009-07-04, 20:58:39
by mysql beginnt mit jedem commit automatisch eine neue transaktion.

jedes statement innerhalb einer transaktion bleibt ein eigenes statement und wird auch somit einzeln ausgeführt

alternativ kannst du auch das INSERT DELAYED mysql kommando verwenden, siehe mysql-doku http://dev.mysql.com/doc/refman/5.1/en/insert.html

Berni
2009-07-05, 03:07:49
Mit prepared Statements ist sowas allerdings nicht zu machen.
Und wieso? Den String, den du an prepare übergibst kannst du doch auch zusammenbauen und dynamisch die Platzhalter einfügen (musst halt durchnummerieren damit sie eindeutig sind). Und anschließend dann halt die Felder "binden" (also so wie samm es geschrieben hat). Performancemäßig bringt das übrigens bei extrem vielen Inserts durchaus Vorteile und gegenüber dem direkten Zusammenbau eines Strings ohne Prepared-Statements hat man eben den Sicherheitsgewinn.

The_Invisible
2009-07-05, 09:10:59
eigentlich sind prepared statements ja gerade dafür optimiert viele gleiche sqls mit anderen daten schnell auszuführen. hab aber produktiv nirgends soviele sqls gleichzeitig das ich was merken würde.

könnte man ja leicht nen benchmark machen mit 1mio inserts oder so.

mfg