Annonce

#1 2006-11-16 12:05:30

Happykiller
Membre
Inscription : 2006-10-24
Messages : 13

Re : Problème de taille de requete avec mass mail

Voila je fait de l'envoi de mass (+500 000) ça marche mais .. j'ai fait des gros trou dans ton code smile et j'aimerais corriger ces trous.

Voila principalement ou j'ai un problème :

abo_id IN(" . implode(', ', $abo_ids) . ")

Comme tu dois t'en douter avec 500 000mails envoyer j'atomise la requete sql, la liste étant bien trop grande sad

Je connais encore mal tout ton code, comme solution je ne vois que l'insertion dans une table temporaire des liste abo_id.

Voila si tu as un conseil je suis preneur smile

ps : il y a un raison particulière pour avoir passé par fichier et non pas une table ?
ps2 : tu travails avec les fichiers lockfile dans engine_send.php, et envoi.php, il y a d'autres ?

Hors ligne

#2 2006-11-19 16:06:31

Happykiller
Membre
Inscription : 2006-10-24
Messages : 13

Re : Problème de taille de requete avec mass mail

Voila les modifications que j'ai apporté afin de garder les possibilités du script et de dépaser le cap de 40 000mails par envoir.

Voila je passe tout l'état des envois en base (question de gout) et procede de façon recurcive pour les mises à jours des états, c'est plus long en therme d'execution mais sans limites au moins.

( ATTENTION je ne suis pas un grand dev, loin de la, j'ai testé chez moi ça marche sans bug, mais c'est pas 100% sur, d'ailleur je suis ouvert à tout commantaire smile )

(Record à 512 867)

Éditez le fichier admin/envoi.php (ligne 236~)

foreach( $liste_ids as $liste_id )
            {
                $lockfile = sprintf(WA_LOCKFILE, $liste_id);
               
                if( file_exists($lockfile) && filesize($lockfile) > 0 )
                {
                    $fp = fopen($lockfile, 'r+');
                   
                    if( flock($fp, LOCK_EX|LOCK_NB) )
                    {
                        $abo_ids = fread($fp, filesize($lockfile));
                        $abo_ids = array_map('trim', explode("\n", trim($abo_ids)));
                       
                        if( count($abo_ids) > 0 )
                        {
                            $abo_ids = array_unique(array_map('intval', $abo_ids));
                           
                            $sql = "UPDATE " . ABO_LISTE_TABLE . "
                                SET send = 1
                                WHERE abo_id IN(" . implode(', ', $abo_ids) . ")
                                    AND liste_id = " . $liste_id;
                            if( !$db->query($sql) )
                            {
                                trigger_error('Impossible de mettre à jour la table des abonnés', ERROR);
                            }
                        }
                       
                        ftruncate($fp, 0);
                        flock($fp, LOCK_UN);
                    }
                   
                    fclose($fp);
                }
            }

En

foreach( $liste_ids as $liste_id )
                {
                    $table_lockfile = "locktable".$liste_id;
                    
                    $sql = "SELECT count(*) FROM ".$table_lockfile.";";
                    if($result = $db->query($sql))
                    {
                        $row = $result->fetch();
                        $count = $row["count(*)"];
                        if($count > 0)
                        {
                            $sql = "SELECT id_email
                            FROM ".$table_lockfile.";";
                            if( !($result = $db->query($sql)) )
                            {
                                trigger_error('Impossible d\'obtenir les données d\'envoi des log', ERROR);
                            }
                            while( $row = $result->fetch() )
                            {
                                $sql2 = "UPDATE " . ABO_LISTE_TABLE . "
                                    SET send = 1
                                    WHERE abo_id = '".$row['id_email']."'
                                    AND liste_id = '" . $liste_id."'";
                                if( !$db->query($sql2) )
                                {
                                    trigger_error('Impossible de mettre à jour la table des abonnés', ERROR);
                                }
                            }
                            
                            $sql = "TRUNCATE TABLE `".$table_lockfile."`;";
                            $result = $db->query($sql);
                        }
                    }
                }

Éditez le fichier include/engine_send.php (ligne 50~)

$lockfile = sprintf(WA_LOCKFILE, $listdata['liste_id']);
   
    if( file_exists($lockfile) )
    {
        $isBeginning = false;
        $fp = fopen($lockfile, 'r+');
        $supp_address = array();// On en tient pas compte, ça l'a déjà été lors du premier flôt
    }
    else
    {
        $isBeginning = true;
        $fp = fopen($lockfile, 'w');
        @chmod($lockfile, 0600);
    }
   
    if( !flock($fp, LOCK_EX|LOCK_NB) )
    {
        fclose($fp);
        return $lang['Message']['List_is_busy'];
    }
   
    if( filesize($lockfile) > 0 )
    {
        //
        // L'envoi a planté au cours d'un "flôt" précédent. On récupère les éventuels
        // identifiants d'abonnés stockés dans le fichier lock et on met à jour la table
        //
        $abo_ids = fread($fp, filesize($lockfile));
        $abo_ids = array_map('trim', explode("\n", trim($abo_ids)));
       
        if( count($abo_ids) > 0 )
        {
            $abo_ids = array_unique(array_map('intval', $abo_ids));
           
            $sql = "UPDATE " . ABO_LISTE_TABLE . "
                SET send = 1
                WHERE abo_id IN(" . implode(', ', $abo_ids) . ")
                    AND liste_id = " . $listdata['liste_id'];
            if( !$db->query($sql) )
            {
                trigger_error('Impossible de mettre à jour la table des abonnés', ERROR);
            }
        }
       
        ftruncate($fp, 0);
        fseek($fp, 0);
    }

EN

$table_lockfile = "locktable".$listdata['liste_id'];
    
    $sql = "SELECT count(*) FROM ".$table_lockfile.";";
    if($result = $db->query($sql))
    {
        $isBeginning = false;
        $supp_address = array();// On en tient pas compte, ça l'a déjà été lors du premier flôt
    }else
    {
        $isBeginning = true;
        $sql = "CREATE TABLE `".$table_lockfile."` (
            `id` INT( 11 ) NOT NULL AUTO_INCREMENT  ,
            `id_email` VARCHAR( 100 ) NOT NULL ,
             PRIMARY KEY ( `id` )
            );";
        $result = $db->query($sql);
        $count = 0;
    }
    
    if($count > 0)
    {
        //
        // L'envoi a planté au cours d'un "flôt" précédent. On récupère les éventuels
        // identifiants d'abonnés stockés dans le fichier lock et on met à jour la table
        //
        $sql = "SELECT id_email
            FROM ".$table_lockfile.";";
        if( !($result = $db->query($sql)) )
        {
            trigger_error('Impossible d\'obtenir les données d\'envoi des log', ERROR);
        }
        while( $row = $result->fetch() )
        {
            $sql2 = "UPDATE " . ABO_LISTE_TABLE . "
                SET send = 1
                WHERE abo_id = '".$row['id_email']."'
                AND liste_id = '" .$listdata['liste_id']."'";
            if( !$db->query($sql2) )
            {
                trigger_error('Impossible de mettre à jour la table des abonnés', ERROR);
            }
        }
            
        $sql = "TRUNCATE TABLE `".$table_lockfile."`;";
        $result = $db->query($sql);
    }

Éditez le fichier include/engine_send.php (ligne 356~)

fwrite($fp, implode("\n", $abo_ids[FORMAT_TEXTE])."\n");

EN

$sql2 = "INSERT INTO `".$table_lockfile."` VALUES('','".$abo_ids[FORMAT_TEXTE]."');";
$result2 = $db->query($sql2);

Éditez le fichier include/engine_send.php (ligne 378~)

fwrite($fp, implode("\n", $abo_ids[FORMAT_HTML])."\n");

EN

$sql2 = "INSERT INTO `".$table_lockfile."` VALUES('','".$abo_ids[FORMAT_TEXTE]."');";
$result2 = $db->query($sql2);

Éditez le fichier include/engine_send.php (ligne 555~)

fwrite($fp, "$row[abo_id]\n");

EN

$sql2 = "INSERT INTO `".$table_lockfile."` VALUES('','".$row['abo_id']."');";
$result2 = $db->query($sql2);

Éditez le fichier include/engine_send.php (ligne 631~)

if( count($abo_ids) > 0 )
    {
        $sql = "UPDATE " . ABO_LISTE_TABLE . "
            SET send = 1
            WHERE abo_id IN(" . implode(', ', $abo_ids) . ")
                AND liste_id = " . $listdata['liste_id'];
        if( !$db->query($sql) )
        {
            trigger_error('Impossible de mettre à jour la table des abonnés (connexion au serveur sql perdue)', ERROR);
        }
    }

EN

if( count($abo_ids) > 0 )
    {
        $sql = "SELECT id_email
            FROM ".$table_lockfile.";";
        if( !($result = $db->query($sql)) )
        {
            trigger_error('Impossible d\'obtenir les données d\'envoi des log', ERROR);
        }
        while( $row = $result->fetch() )
        {
            $sql2 = "UPDATE " . ABO_LISTE_TABLE . "
                SET send = 1
                WHERE abo_id = '".$row['id_email']."'
                AND liste_id = '" .$listdata['liste_id']."'";
            if( !$db->query($sql2) )
            {
                trigger_error('Impossible de mettre à jour la table des abonnés', ERROR);
            }
        }
    }

Éditez le fichier include/engine_send.php (ligne 579~)

flock($fp, LOCK_UN);
                fclose($fp);
                unlink($lockfile);

EN

$sql = "DROP TABLE `".$table_lockfile."`;";
$result = $db->query($sql);    

Éditez le fichier include/engine_send.php (ligne 668~)

ftruncate($fp, 0);
    flock($fp, LOCK_UN);
    fclose($fp);

EN

$sql = "TRUNCATE TABLE `".$table_lockfile."`;";
$result = $db->query($sql);

Éditez le fichier include/engine_send.php (ligne 684~)

unlink($lockfile);

EN

$sql = "DROP TABLE `".$table_lockfile."`;";
$result = $db->query($sql);    

Hors ligne

#3 2006-11-21 14:41:40

Bobe
Administrateur
Lieu : La Rochelle
Inscription : 2002-05-27
Messages : 5 299

Re : Problème de taille de requete avec mass mail

ps : il y a un raison particulière pour avoir passé par fichier et non pas une table ?

Oui, j'ai jugé insensé d'envoyer, pour reprendre ton cas, 500000 requêtes SQL dans la tronche du serveur de base de données. :-)

ps2 : tu travails avec les fichiers lockfile dans engine_send.php, et envoi.php, il y a d'autres ?

Non, que dans ces deux fichiers.

Pourquoi ne fais-tu pas tes envois par flot. En faisant tes envois par flot de 40000 par exemple.

Ou utilise le script contrib/wanewsletter pour faire tes envois en ligne de commande et utilise l'option --limit=40000 pour que le script n'envoie que 40000 emails (ce qui limite du même coup la taille de la requête sql).


PHP et MySQL, un duo gagnant !

Hors ligne

#4 2006-11-21 16:17:38

Happykiller
Membre
Inscription : 2006-10-24
Messages : 13

Re : Problème de taille de requete avec mass mail

j'utilse "contrib/wanewsletter" bien entendu ^^ et l'option limit, les 460 000 autres mails je fait comment pour les envoyer ?

ps : ben pour etre franc mes process mysql ne depase pas 40% en resources sur l'envoi de 500 000 donc bof ça dérange pas plus que ça.

Hors ligne

#5 2006-11-22 13:19:37

rateck
Membre
Inscription : 2006-02-24
Messages : 54

Re : Problème de taille de requete avec mass mail

Cette approche de gestion du Lock dans une table me plait car elle pourrait permettre d'apporter plus de souplesse (en particulier dans le cadre d'envoi de plusieurs mails à la même liste me semble-t-il!) et d'homogénéité à WNL  (tout est géré en BD).
Question consommation de CPU, il me semble que la requête de mise à jour de la table "ABO_LISTE_TABLE" doit grandement améliorier les performances car elle est effectuée à travers la valeur de Index ("WHERE abo_id = '".$row['id_email']."'AND liste_id = '" . $liste_id."'") et non à travers le parcours de l'Index/table (WHERE abo_id IN(" . implode(', ', $abo_ids) . ") AND liste_id = " . $listdata['liste_id']).
Je vote donc pour que Bobe la prenne en compte dans une prochaine version si cela est possible.
NB: Sur certain moteur de BD, l'utilisation d'une fonction sur la valeur de l'occurrence à rechercher désactive l'utilisation de(s) l'Index.

Hors ligne

#6 2006-12-11 14:38:39

rikewir
Membre
Inscription : 2006-12-11
Messages : 1

Re : Problème de taille de requete avec mass mail

En mode : 1 abonnée = 1 mail
J'ai fait un premier essai sur une liste de 30 000 abonnées et je n'ai eu aucun soucis.
Je viens de faire un essai sur une liste de 85 000 abonnées et la ça bloque à peut prêt tous les 5 000 mails envoyés … En cours d'envoie d'ai testé un changement de mode et j'ai eu le message d'erreur suivant à la reprise de l'envoie : « L'email n'a pu être envoyé ! Fichier : engine_send.php Ligne : 375 »
Je pense que ses modifications sont intéressantes mais je ne préfère pas prendre le risque d'essayer … Je préfère attendre une version qui gère mieux les mailings « important ».

Hors ligne

Pied de page des forums