php
  • mysql
  • 2008-10-17 7 views 5 likes 
    5

    Je recherche le code comme ceci:Comment construire de grandes requêtes MySQL INSERT en PHP sans perdre la mémoire

    $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); 
    

    Je sais que ce n'est pas très efficace car chacun des « » les opérateurs réalloueront un plus grand bloc de mémoire et la chaîne de 30 Mo sera copiée plusieurs fois.

    Y a-t-il quelque chose de plus efficace que la solution suivante?

    $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))); 
    

    Répondre

    7

    Vous avez deux questions:

    # 1, il y a plusieurs façons différentes, vous pouvez calculer le hachage MD5:

    • Faites comme vous le faites et la charge en PHP comme une chaîne et utiliser PHP de md5()
    • utilisez md5_file() de PHP
    • PHP 5.1+, vous pouvez utiliser l'API de flux de PHP avec l'une des md5 ou md5_file pour éviter de charger entièrement en mémoire
    • Utilisez exec() pour appeler md5sum commande
    • Utilisez la fonction MySQL de MD5() pour calculer le hachage

    du système Puisque ce sont trivial à mettre en œuvre, il serait facile pour vous de mettre en œuvre et référence tous pour l'utilisation de la mémoire et la vitesse. Voici some benchmarks montrant le système md5 via exec pour être beaucoup plus rapide que PHP md5_file comme la taille du fichier augmente. Le faire à votre façon est certainement le pire moyen en ce qui concerne l'utilisation de la mémoire.

    # 2, mysql_real_escape_string effectue une requête de base de données, donc vous transmettez vos données blob à la base de données, récupérez-les en tant que chaîne et transmettez-les à nouveau (!) Avec la requête INSERT. Donc, il se déplace vers/depuis le serveur DB 3x au lieu de 1x et en utilisant 2x la mémoire en PHP.

    Il va être plus efficace d'utiliser PHP5 prepared statements et seulement envoyer ces données à la base de données une fois. Lisez la section de l'article lié, vous verrez qu'il mentionne que lorsque vous liez des paramètres, vous pouvez utiliser le type de blob pour diffuser des données BLOB à la DB en morceaux. Les PHP docs for mysqli_stmt::send_long_data en ont un excellent exemple simple: INSÉRER un fichier dans une colonne BLOB comme vous l'êtes.

    En faisant cela, et en utilisant l'API de flux, md5_file ou exec avec la commande md5 du système, vous pouvez faire votre entière INSERT sans charger jamais le fichier en mémoire, ce qui signifie l'utilisation de la mémoire pour votre série d'opérations peut soyez aussi bas que vous voulez!

    0

    Avez-vous référencé l'astuce de tampon de sortie? Une autre chose que vous pourriez faire est de convertir en mysqli ou MDB2, qui prennent en charge les paramètres liés. Cela vous permettrait d'ignorer l'appel mysql_real_escape_string et les concaténations de chaînes.

    -1

    Bien, si l'utilisation de la mémoire est votre problème, vous pouvez lire le gros fichier en morceaux et insérer ces morceaux avec CONCAT dans le champ de base de données.

    Exemple de code (non testé):

    $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); 
        } 
    

    Cette méthode sera plus lent, mais vous aurez besoin que 4Ko de mémoire.

    3

    Si vous utilisez PDO et que vous avez préparé des statuts, vous pouvez utiliser le type PDO :: PARAM_LOB. Voir l'exemple n ° 2 sur la page LOB montrant comment insérer une image dans une base de données en utilisant le pointeur de fichier.

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

    +0

    Problème avec PDO est qu'il émule seulement les instructions préparées si vous n'avez pas la bibliothèque mysqli. Tout ce que cela fait est de déplacer le concaténer dans la bibliothèque PDO. – jmucchiello

    0

    Ne serait-il faire une différence si vous ne mettez pas la requête dans une autre variable, mais plutôt passer directement dans la commande MySQL. Je n'ai jamais essayé cela, mais cela peut faire la différence car toute la chaîne n'est pas stockée dans une autre variable.

    Questions connexes