2008-10-17 17 views
5

He código buscando algo como esto:Cómo construir grandes consulta MySQL INSERT en PHP sin perder la memoria

$data = file_get_contents($tempFile); // perhaps 30MB of file data, now in PHP's memory 
$hash = md5($data); 
$query = "INSERT INTO some_table 
      SET BlobData = '" . mysql_real_escape_string($data) . "', 
      BlobHash = '$hash' 
      "; 
mysql_query($query); 

Sé que esto no es muy eficiente ya que cada uno de los ''. los operadores reasignarán un bloque de memoria más grande y la cadena de 30MB se copiará varias veces.

¿Hay algo más eficiente que la siguiente solución?

$data = file_get_contents($tempFile); // perhaps 30MB of file data, now in PHP's memory 
$hash = md5($data); 
$query = "INSERT INTO some_table SET BlobData = '%s', BlobHash = '$hash'"; 
mysql_query(sprintf($query, mysql_real_escape_string($data))); 

Respuesta

7

Hay dos cuestiones aquí:

nº 1, hay varias maneras diferentes que puede calcular el hash MD5:

  • Haz lo que haces y cargar en PHP como una cadena y usar PHP de md5()
  • uso de PHP md5_file()
  • a partir de PHP 5.1 o superior puede utilizar API de secuencias de PHP con cualquiera de md5 o md5_file para evitar cargar por completo en la memoria
  • Uso exec() para llamar a la orden del sistema de md5sum
  • función
  • de Uso MySQL MD5() para calcular el hash

Dado que todos estos son triviales para poner en práctica, sería fácil para que usted pueda poner en práctica y de referencia a todos ellos por el uso de memoria y velocidad. Aquí están some benchmarks mostrando el sistema md5 a través de exec que es mucho más rápido que el md5_file de PHP a medida que aumenta el tamaño del archivo. Hacerlo a tu manera es definitivamente la peor manera en lo que respecta al uso de la memoria.

# 2, mysql_real_escape_string realiza una consulta de base de datos, por lo que en realidad está transmitiendo sus datos de blob a la base de datos, obteniéndolo como una cadena y transmitiéndolo nuevamente (!) Con la consulta INSERTAR. Por lo tanto, se viaja hacia/desde el servidor de base de datos 3 veces en lugar de 1 vez y utilizando 2 veces la memoria en PHP.

Va a ser más eficiente usar PHP5 prepared statements y solo enviar esta información a la base de datos una vez. Lea la sección del artículo enlazado, verá que menciona que cuando está vinculando parámetros, puede usar el tipo de blob para transmitir los datos de blobs al DB en fragmentos. El PHP docs for mysqli_stmt::send_long_data tiene un gran ejemplo simple de esto que inserta un archivo en una columna de blob como usted.

Al hacer esto, y mediante el uso de cualquiera de la API de secuencias, md5_file o exec con el comando md5 sistema, puede hacer toda su INSERT sin tener que cargar el archivo en la memoria, lo que significa el uso de memoria para su serie de operaciones puede ¡tan bajo como quieras!

0

¿Ha evaluado el truco de salida del buffering?

ob_start(); 
echo 'INSERT INTO some_table SET BlobData = \'', mysql_real_escape_string($data), '\', BlobHash = \'', $hash, '\''; 
mysql_query(ob_get_clean()); 

Otra cosa que podría hacer es convertir a mysqli o MDB2, que admiten los parámetros vinculados. Eso le permitiría omitir la llamada mysql_real_escape_string y las concatenaciones de cadena.

-1

Bueno, si su problema es el uso de la memoria, puede leer el archivo grande en trozos e insertar estos trozos con CONCAT en el campo de la base de datos.

Código de la muestra (no probado):

$id = 1337; 
$h = fopen("path/to/file.ext", "r"); 
while (!feof($h)) 
    { 
    $buffer = fread($h, 4096); 
    $sql = "UPDATE table SET my_field = CONCAT(my_field, '" . mysql_real_escape_string($buffer) . "') WHERE Id = " . $id; 
    mysql_query($sql); 
    } 

Este método será más lenta pero usted sólo requieren 4 Kb de memoria.

3

Si está utilizando PDO y declaraciones preparadas, puede usar el tipo PDO :: PARAM_LOB. Vea el ejemplo # 2 en la página LOB que muestra cómo insertar una imagen en una base de datos usando el puntero del archivo.

http://us2.php.net/manual/en/pdo.lobs.php

+0

Problema con PDO es que solo emula declaraciones preparadas si no tiene la biblioteca mysqli. Entonces todo lo que hace es mover la concatenación a la biblioteca PDO. – jmucchiello

0

¿habría alguna diferencia si usted no puso la consulta en otra variable, pero en cambio se lo pasó directamente en el comando de MySQL. Nunca he intentado esto, pero puede hacer una diferencia ya que toda la cadena no está almacenada en otra variable.

Cuestiones relacionadas