Preparación de sentencias SQL con PDO

Mi código se ve así:

// Connect to SQLite DB DB('/path/to/sqlite.db'); DB('BEGIN TRANSACTION;'); // These loops are just examples. for ($i = 1; $i <= 10000; $i++) { for ($j = 1; $j <= 100; $j++) { DB('INSERT INTO "test" ("id", "name") VALUES (?, ?);', $i, 'Testing ' . $j); } } DB('END TRANSACTION;'); 

Y aquí está la función DB ():

 function DB($query) { static $db = null; if (is_file($query) === true) { $db = new PDO('sqlite:' . $query, null, null, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING)); } else if (is_a($db, 'PDO') === true) { $result = $db->prepare($query); if (is_a($result, 'PDOStatement') === true) { if ($result->execute(array_slice(func_get_args(), 1)) === true) { if (stripos($query, 'INSERT') === 0) { return $db->lastInsertId(); } if (stripos($query, 'SELECT') === 0) { return $result->fetchAll(PDO::FETCH_ASSOC); } return $result->rowCount(); } } return false; } return true; } 

El problema es que la llamada DB () dentro del ciclo interno tarda mucho en completarse, estaba pensando que hacer algo como esto podría acelerar considerablemente la ejecución:

 DB('BEGIN TRANSACTION;'); for ($i = 1; $i <= 10000; $i++) { $queries = array(); for ($j = 1; $j <= 100; $j++) { $queries[] = 'INSERT INTO "test" ("id", "name") VALUES (?, ?);' /*, $i, 'Testing ' . $j;*/ } DB(implode("\n", $queries)); } DB('END TRANSACTION;'); 

El problema es que no sé cómo podría preparar (reemplazar y escapar) todos los signos de interrogación con las variables respectivas, ¿hay alguna forma de que pueda lograr esto?

Si está insertando muchos datos en una tabla, intente insertar los datos en una consulta.

 $query = 'INSERT INTO "test" ("id", "name") VALUES '; $data = array(); for ($i = 1; $i <= 10000; $i++) { for ($j = 1; $j <= 100; $j++) { $query .= '(?,?),'; $data[] = $i; $data[] = 'Testing '.$j; } } $query = substr($query, 0, -1); DB($query, $data); 

Esto debería eliminar la sobrecarga con consultas de inserción única. Sin embargo, hay un límite en la duración de la consulta, si tiene problemas con la longitud de la consulta, intente emitir llamadas DB () con mayor frecuencia en for loop.

¿Por qué usa declaraciones preparadas si las “prepara” en el ciclo? (en la función DB)

Haga una preparación antes del bucle, y en el bucle solo dé los valores y ejecútelos. Por supuesto, esto requeriría una reescritura de su método DB.

Oh y por cierto. ¿Tu columna de ID es la clave principal? si es así tienes otro problema porque “yo” sería por 100 “j” igual 🙂

Por ejemplo:

 $sth = $dbh->prepare('INSERT INTO "test" ("id", "name") VALUES (:id, :name)'); $j=0; for ($i = 1; $i <= 10000; $i++){ $j = ($j==100) ? 0 : $j++; $sth->execute(array(':id' => $i, ':name' => 'Testing ' . $j)); } 

Desafortunadamente, creo que el problema puede estar en la estructura de tu código.

En su ciclo de instrucciones INSERT, las declaraciones son todas idénticas y no hay necesidad de llamar $ db-> preparar cada vez. La idea detrás de las declaraciones preparadas es que llame a $ db-> prepare () una vez, y execute () se puede llamar varias veces en el mismo objeto de statement. Está llamando $ db-> prepare () cada vez, lo que está causando gastos generales en el análisis de la statement SQL y la creación de un nuevo objeto.

Considere volver a escribir su función DB () como esta:

 function do_query($db, $pdo_statement, $query, $args) { if ($pdo_statement->execute($args) === true) { if (stripos($query, 'INSERT') === 0) { return $db->lastInsertId(); } if (stripos($query, 'SELECT') === 0) { return $result->fetchAll(PDO::FETCH_ASSOC); } return $result->rowCount(); } } function DB($query) { static $db = null; if (is_file($query) === true) { $db = new PDO('sqlite:' . $query, null, null, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING)); } else if (is_a($db, 'PDO') === true) { $result = $db->prepare($query); if (is_a($result, 'PDOStatement') === true) { $args = func_get_args(); if (is_array($args[1])) { $ret = array(); foreach ($args[1] as $args) { $ret[] = do_query($db, $query, $result, $args); } return $ret; } return do_query($db, $query, $result, array_slice(func_get_args(), 1)); } return false; } return true; } 

Entonces, si desea ejecutar la misma consulta con muchos valores, crea una matriz bidimensional de los valores que desea insertar y llama a DB('INSERT INTO....', $values) . La función DB () comprueba si el segundo parámetro de la función (después de $ query) es una matriz y, de ser así, realiza un bucle ejecutando $ query con los valores de la matriz. De esta forma, el ciclo no implica volver a preparar la statement de SQL cada vez, solo volver a ejecutarla con diferentes valores. El valor de retorno de la función será una matriz de los resultados de cada consulta.

La función DB, tal como se publicó originalmente, emite una llamada al sistema de sistema de archivos stat () cada vez que se ejecuta para verificar si la cadena de consulta es un archivo. Si bien eso no es el único responsable de la ejecución lenta, contribuye a ello.