php PDO insertion par lots de plusieurs lignes avec des espaces réservés
Je suis à la recherche de faire plusieurs insertions à l'aide de PHP PDO.
Le plus proche de la réponse que j'ai trouvé est celui-ci
comment insérer un tableau-en-un-seul-mysql-préparé-déclaration
Cependant l'exemple des thats été donné utilise ?? au lieu de vrais espaces réservés.
J'ai regardé les exemples sur la doc PHP site pour les détenteurs de place
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
$stmt->bindParam(':name', $name);
$stmt->bindParam(':value', $value);
Maintenant, disons que je voulais atteindre les ci-dessus, mais avec un tableau
$valuesToInsert = array(
0 => array('name' => 'Robert', 'value' => 'some value'),
1 => array('name' -> 'Louise', 'value' => 'another value')
);
Comment m'y prendre avec PDO et plusieurs inserts par transaction?
J'imagine qu'il en serait de commencer avec une boucle?
$stmt = $dbh->prepare("INSERT INTO REGISTRY (name, value) VALUES (:name, :value)");
foreach($valuesToInsert as $insertRow){
//now loop through each inner array to match binded values
foreach($insertRow as $column => value){
$stmt->bindParam(":{$column}", value);
}
}
$stmt->execute();
Cependant, le ci-dessus ne fonctionne pas, mais j'espère qu'il va démontrer ce que im essayant d'atteindre
- vous avez besoin d'exécuter à l'intérieur de la boucle. sinon, vous êtes juste d'écraser le paramètre de limite et à la fin de la liaison uniquement la DERNIÈRE valeur.
- cependant, si j'exécute alors qui va faire la DB transaction une ligne à la fois? Im essayant de le faire dans le lot
- oui, mais si vous êtes en essayant d'imiter le mysql étendu
insert ... values (...), (...), (...)
insérer syntaxe, ce n'est pas la façon dont vous aller à ce sujet. vous devez pré-construire une instruction de requête qui a un espace réservé pour chaque ensemble de valeurs de l'insertion, de la préparer, lier des paramètres, puis sur exécuter. vous auriez du faire autant de travail que l'exécution d'une seule préparé insérer plusieurs fois. - Je suis de l'insertion de quelques 40 ou 50 lignes à la fois. J'ai besoin de le faire dans le lot. Son la DB opération qui prend du temps.
- Puis enveloppez le tout en une seule opération à l'aide de la fonction PDO::beginTransaction() / PDO::commit() et d'exécuter des requêtes comme mentionné par @MarcB.
- JFYI:
??
sont réel des espaces et des:name
sont des faux. - comment dois-je faire PDO::beginTransaction() / PDO::commit()
Vous devez vous connecter pour publier un commentaire.
Tout d'abord,
?
symboles sont lieu réel-titulaires (la plupart des pilotes permettent d'utiliser les deux syntaxes, de position et de lieu nommé-titulaires). Deuxièmement, les requêtes préparées ne sont rien, mais un outil pour injecter des entrées brutes en instructions SQL—la syntaxe de l'instruction SQL lui-même n'est pas affectée. Vous avez déjà tous les éléments dont vous avez besoin:Il est assez trivial de les combiner:
array_chunk
array_chunk
avec 100 lignes a réalisé un 2x la vitesse maximum par rapport à la normale pour la boucle sur InnoDB utilise des transactions. Lots plus importants de ne pas aller plus vite.Je suis en supposant que vous utilisez InnoDB si cette réponse n'est valable que pour le moteur (ou de toute autre opération capable de moteur, sens MyISAM n'est pas inclus).
Par défaut InnoDB fonctionne en mode auto-commit. Cela signifie que chaque requête est traitée comme ses propres contenus transaction.
Pour traduire cela en quelque chose de nous, le commun des mortels peut comprendre, cela signifie que chaque requête d'INSERTION vous question de volonté de la force de disque dur à la commettre en confirmant qu'il a écrit les informations de la requête.
Considérant la façon dont dur mécanique-les disques sont super lent depuis leur entrée-sortie de l'opération par seconde est faible (si je ne me trompe pas, la moyenne est de 300ish IO), cela signifie que votre 50 000 requêtes seront - bien, super lent.
Alors que faites-vous? Vous vous engagez tous vos 50k requêtes en une seule transaction. Il pourrait ne pas être la meilleure solution à des fins diverses, mais ça va être rapide.
Vous de faire comme ceci:
LOAD DATA INFILE
est toujours l'option la plus rapide et la construction d'un fichier destiné à être utilisé avecLOAD DATA INFILE
devrait être assez simple. J'ai oublié d'ajouter que, pour la réponse, et comme @ÁlvaroG.Vicario mentionné -INSERT INTO .... VALUES..
est plus rapide que l'exécution d'une instruction préparée dans la boucle.Un peu de modifications dans la solution fournie par N. B
$stmt->execute() doit être en dehors de la boucle interne parce que vous pouvez avoir un ou plusieurs colonnes qui ont besoin de lier avant d'appeler $stmt->execute() sinon, vous 'll obtenir exception "Invalid parameter number: number of bound variables ne correspond pas à un nombre de jeton".
2ème valeur "variable" ont disparu des signes dollar.
Test:
Votre code a été fait ok, mais a eu un problème dans
$stmt->bindParam(":$column", value);
Il devrait être$stmt->bindValue(":{$column}", $value);
et cela fonctionnera parfaitement. Cela permettra d'aider d'autres dans le futur.Code complet:
Déplacer exécuter à l'intérieur de la boucle.
Si vous rencontrez des problèmes avec cette méthode recommandée, vous devez vous poser une question, la description de ces de certains problèmes.