Page 1 sur 1

Les boucles en php

Posté : 15 sept. 2014, 10:10
par djimy_cartel
Bonjour à tous;

Voilà , j'ai écris un script php qui a pour but de compter le nombre d'enregistrements dans une table qui s'appelle "mdl_log" de ma base de données "moodle" , si ce nombre dépasse 100000, alors il crée une nouvelle table appelée "mdl_log1" , il insère les 100000 premiers enregistrements dans cette dernière puis il les supprime dans la table d'origine ,c'est à dire dans "mdl_log". Voici mon script:
set_time_limit(0);
$debut= date('H:i:s');
//die();

include ('connection.php');

$db=mysql_select_db("moodle");
///////////////////////////
$sql_cpt= "SELECT COUNT(id) as NBR FROM mdl_log";
$res_sql_cpt=mysql_query($sql_cpt);
if($res_sql_cpt==FALSE)
{die(mysql_error());
mysql_close();}
$rep_sql_cpt= mysql_fetch_array($res_sql_cpt);
{
mysql_free_result($res_sql_cpt);
$NBR=$rep_sql_cpt['NBR'];
echo ' nbr= '.$NBR;
}

if($NBR>=100000)
{

$sql_create="CREATE TABLE `moodle`.`mdl_log1` (`id` bigint( 10 ) NOT NULL AUTO_INCREMENT ,`time` bigint( 10 ) NOT NULL DEFAULT '0',`userid` bigint( 10 ) NOT NULL DEFAULT '0',`ip` varchar( 45 ) NOT NULL DEFAULT '',`course` bigint( 10 ) NOT NULL DEFAULT '0',`module` varchar( 20 ) NOT NULL DEFAULT''`cmid` bigint( 10 ) NOT NULL DEFAULT '0',`action` varchar( 40 ) NOT NULL DEFAULT '',`url` varchar( 100 ) NOT NULL DEFAULT '',`info` varchar( 255 ) NOT NULL DEFAULT '',PRIMARY KEY ( `id` ) ,KEY `mdl_log_coumodact_ix` ( `course` , `module` , `action` ) ,
KEY `mdl_log_tim_ix` ( `time`),KEY`mdl_log_act_ix` ( `action` ) ,
KEY `mdl_log_usecou_ix` ( `userid` , `course` ) ,
KEY `mdl_log_cmi_ix` ( `cmid` ))";

$res1=mysql_query($sql_create);
if ($res1==FALSE)
echo mysql_error();
$sql_insert="INSERT INTO `moodle`.`mdl_log1` (SELECT* FROM `moodle`.`mdl_log`   WHERE `mdl_log`.`id` >=1 AND `mdl_log`.`id`<=100000)
";
$res_sql_insert=mysql_query($sql_insert);
if ($res_sql_insert==FALSE)
echo mysql_erreur();

mysql_close();
$sql_suppr="DELETE FROM `moodle`.`mdl_log` WHERE `mdl_log`.`id`>=1  AND `mdl_log`.`id`<=100000";
$res_sql_suppr=mysql_query($sql_suppr);
if ($res_sql_suppr==FALSE)
echo mysql_erreur();
}
}
mysql_close();
    
Sachant que le champs 'id' est incrémenté automatiquement et que le nombre d'enregistrements augmente d'une manière rapide , par conséquent , j'aurais besoin de plusieurs tables et pas seulement d'une seule comme je l'ai fait dans le script et que les enregistrements à insérer seront toujours les 100000 premiers: Je m'explique: pour la première table mdl_log1, les enregistrements à insérer commenceront à partir de 1 jusqu'à 100000. Pour la deuxième table mdl_log2, les enregistrements à insérer commenceront à partir de 100001 à 200001 et ainsi de suite..
Pourrez-vous me dire comment améliorer mon script afin qu'il réponde à mes besoins?
Désolé pour ce long message et merci d'avance.

Re: Les boucles en php

Posté : 15 sept. 2014, 11:01
par sirakawa
Une remarque:
moi aussi je mettais des ` ` autour des noms de tables et de champs; mais j'ai lu danx les consignes de je nesais plus quel site institutionnel qu'il fallait les proscrire.
Une suggestion
au lieu d'écrire "INSERT into moodle.moodle_log1...where ... 100000"
si tu écrivais
$tables = array ("moodle_log1", 10000),
   array ("moodle_log2", "200000),
);
et en allant voir du coté de array_walk?

Re: Les boucles en php

Posté : 15 sept. 2014, 12:00
par djimy_cartel
Merci beaucoup sirakawa pour la remarque, ça je ne le savais pas avant , mais le problème maintenant est comment améliorer mon script?

Re: Les boucles en php

Posté : 15 sept. 2014, 12:30
par ynx
Salut,

Avant d'essayer d'améliorer ton script, quel est l'intérêt de réaliser cette opération ? En effet les tables mysql sont faites pour gérer plusieurs millions d'enregistrements sans problèmes.
Peux-tu nous expliquer quel est le besoin final de cette opération (si ce n'est pas trop indiscret ^^), nous pourrons p-e te proposer une solution qui conviendrais mieux à la problématique.

Bonne journée

Re: Les boucles en php

Posté : 15 sept. 2014, 12:59
par sirakawa
Autant je comprendrais que l'onveuille faire des sauvegardes (moodle ne l'ayant peut etre pas prévu) autant je comprends moins ce besoin; à moins que moodle ait une limite.
Je pense qu'il faudrait creuser mon idée de tableau et array_walk;;;;

Re: Les boucles en php

Posté : 15 sept. 2014, 13:03
par djimy_cartel
Merci ynx , effectivement les tables Mysql sont faites pour gérer des millions d’enregistrements sans problème, mais l'année passée, on est tombés dans une situation très délicate où notre base de données 'moodle' a craché à cause de nombre d'enregistrements élevé dans la table mdl_log, je m'explique: on travail dans établissement d'enseignement à distance , pour cela, on a opté pour une plate-forme d'enseignement en ligne qui est 'moodle', la table 'mdl_log' garde automatiquement l'historique de nos élèves et comme nous avons un nombre énorme d'apprenants (plus de 500000) , le nombre d'enregistrements dans la table augmente au moyenne de 1000000 par jour.Ce qui nous a obligé de vider notre table quotidiennement afin d'éviter les problèmes, mais malheureusement cette opération été manuelle , cette année , nous voulons l'automatiser à l'aide d'un script php qui s’exécutera régulièrement avec cron.

Re: Les boucles en php

Posté : 15 sept. 2014, 15:06
par ynx
Ok donc nous ne pouvons pas vraiment te proposer de solution alternative.

Donc pour améliorer ton script, on peut commencer par simplifier la création de la nouvelle table. Tu peux utiliser la syntaxe suivante pour copier la structure d'une table à l'identique :
CREATE TABLE nouvelle_table LIKE table_origine;
Ensuite pour trouver le nom de la nouvelle table à créer en fonction de celles déjà existantes, tu peux procéder comme ceci :
SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'nom de la base' AND TABLE_NAME LIKE 'mdl_log%'
Cette requête retourne toutes les tables qui commencent par la chaine 'mdl_log', nous aurons donc par exemple : mdl_log1, mdl_log2, mdl_log3
(Attention à bien renseigner le 'nom de la base' si ton SGBD contient plusieurs bases avec des tables mdl_log)

Puisque c'est le numéro de la table qui nous intéresse, on peut effectuer un SUBSTRING pour ne récupérer que cette partie. Enfin puisque nous voulons récupérer le numéro de la nouvelle table à créer, qui correspond au numéro maximum de la requête précédente + 1, on peut effectuer la requête suivante :
SELECT MAX(SUBSTRING(TABLE_NAME FROM 8) + 1) FROM information_schema.TABLES WHERE TABLE_SCHEMA = 'nom de la base' AND TABLE_NAME LIKE 'mdl_log%'
Si la base contient mdl_log1 et mdl_log2, cette requête retournera 3
Si la base contient mdl_log1, mdl_log2 et mdl_log3, cette requête retournera 4
etc...

A partir de ce numéro le reste du script est relativement facile à adapter.

Bon développement

Re: Les boucles en php

Posté : 15 sept. 2014, 16:45
par djimy_cartel
Merci , je vais essayer de procéder comme vous m'avez dit.

Re: Les boucles en php

Posté : 16 sept. 2014, 04:20
par JokerMentalist
Bonjour,

Je te recomande d'utiliser la POO pour ton script ! en effet moi j'aurais créer une class pour la BDD et une class pour ton action :

Un petit exemple de script :
<?php
class sql {
    
    private $host="localhost"; 
    private $dbname="ta base";
    private $dbpassword="";
    private $dbuser="root";
    private $debug="ERRMODE_WARNING";
    
    public $datab;
    public $sql;
    
    
            
    function __construct() {
        try{
            $this->datab = new PDO('mysql:host='.$this->host.';dbname='.$this->dbname,$this->dbuser,$this->dbpassword,array(PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8'));
            $this->datab->setAttribute(PDO::ATTR_ERRMODE,PDO::$this->debug);
        }catch(PDOException $e){
            echo 'Il y à un soucis de Connexion à mysql';
        }
    }
    
    function doReq($sql,$result=true){
        
        $this->sql=$sql;
        $pre=$this->datab->query($sql);
        if($result){
            $d = $pre->fetchAll(PDO::FETCH_OBJ);
            return $d;
        }
    }
}
Voila comme ca tu as un bojet que tu poura utiliser dans d'autres scripts !

Maintenant tu as une partie a créer qui te scan la table et l'archive en fonction de la taille.
<?php
class archiver {
    var $db;
    
    function __construct() {
        // Pour simplifier tes requettes :
        require('taclassPDO.php');
        $this->db=new sql();
        //on stock ca dans l'instance de class
        //on compte le nombre d'entrées dans la table
        if($this->countInputs()){
            newTable();
        }
    }
    /**
     * Vérifie si le nombre d'enregistrements est inférieur à 1000
     * @return boolean
     */
    function countInputs() {
        $res=$this->db->doReq("SELECT * FROM mdl_log");
        if(count($res)>10000){
            return true;
        }else{
            return false;
        }
    }
    /**
     * Pour créer une table automatiquement
     * 
     * 
     */
    function newTable() {
        
        //on crée la table d'indexation
        $sqlIndexation = " CREATE TABLE IF NOT EXISTS `mdl_log_index` ( 
        `id`        bigint( 10 )    NOT NULL AUTO_INCREMENT, 
        `start_id`  bigint( 10 )    NOT NULL DEFAULT '0', 
        `end_id`    bigint( 10 )    NOT NULL DEFAULT '0', 
        PRIMARY KEY ( `id` ))";
        //si la table d'incexation existe on ne la crée pas
        $this->db->doReq($sqlIndexation);
        //on récupére les enregistrements
        $archivage_fields=$this->db->doReq("SELECT * FROM mdl_log LIMIT 10000 ORDER BY id ASC");
        //on créer le nouvel index
        $n=count($archivage_fields);
        $firstId=$archivage_fields['0']->id;
        $lastId=$archivage_fields[$n-1]->id;
        $this->db->doReq("INSERT INTO `mdl_log_index` VALUE('', '$firstId', '$lastId')");
        //on récupére l'id créer grace à une requette (question de gout perso)
        $numeroDeTable=  $this->db->doReq("SELECT * FROM mdl_log_index WHERE `start_id`='$firstId' AND `end_id`='$lastId'");
        $number=$numeroDeTable['0']->id;
        //ya plus q'a créer la table
        $sql = "CREATE TABLE `mdl_log_".$number."` ( 
        `id`        bigint( 10 )    NOT NULL AUTO_INCREMENT, 
        `time`      bigint( 10 )    NOT NULL DEFAULT '0', 
        `userid`    bigint( 10 )    NOT NULL DEFAULT '0', 
        `ip`        varchar( 45 )   NOT NULL DEFAULT '', 
        `course`    bigint( 10 )    NOT NULL DEFAULT '0', 
        `module`    varchar( 20 )   NOT NULL DEFAULT '', 
        `cmid`      bigint( 10 )    NOT NULL DEFAULT '0', 
        `action`    varchar( 40 )   NOT NULL DEFAULT '', 
        `url`       varchar( 100 )  NOT NULL DEFAULT '', 
        `info`      varchar( 255 )  NOT NULL DEFAULT '',
        PRIMARY KEY ( `id` ) ,
        KEY `mdl_log_coumodact_ix` ( `course` , `module` , `action` ) ,
        KEY `mdl_log_tim_ix` ( `time`),
        KEY`mdl_log_act_ix` ( `action` ) ,
        KEY `mdl_log_usecou_ix` ( `userid` , `course` ) ,
        KEY `mdl_log_cmi_ix` ( `cmid` ))";
        $this->db->doReq($sql);
        $sqlD="INSERT INTO `mdl_log_".$number."` VALUE ";
        //puis on insert les resultats
        foreach ($archivage_fields as $key => $value) {
           $sqlD.= '('.$value->id.', '.$value->time.', '.$value->userid.', '.$value->ip.', '.$value->course.', '.$value->module.', '.$value->cmid.', '.$value->action.',  '.$value->url.', '.$value->info.'),';
        }
        //on insert
        $this->db->doReq($sqlD);
        //puis on efface
        $this->db->doReq("DELETE FROM `mdl_log` WHERE `id` > '$firstId' AND `id` > '$lastId' LIMIT 10000");
    }
}
tu range ces deux fichier dans un repertoire tu require le fichier archiver.
tu fait juste un petit new archiver().
Puis tu relance ce script quand tu veux archiver avec une tache planifier de ton serveur et l'affaire est réglé.

voici mon mail contact moi n'hesite pas
[email protected]
bye ..

Re: Les boucles en php

Posté : 22 sept. 2014, 16:21
par djimy_cartel
Salut à tous;

Merci pour votre aide , comme je suis débutant en php alors, vos propositions sont un peu compliquées pour moi , c'est pour ça que j'ai opté pour une autre solution plus simple qui marche très bien même avec le cron, voici le code pour ceux qui tombent dans le même cas que moi.
<?php
date_default_timezone_set('Africa/Algiers') ;
set_time_limit(0);
$debut= date('H:i:s');
//die();

include ('connection.php');
$db=mysql_select_db("moodle");
///////////////////////////
$sql_min= "SELECT MIN(id) as VAL_MIN FROM mdl_log";
$res_sql_min=mysql_query($sql_min);
if($res_sql_min==FALSE)
{die(mysql_error());
mysql_close();}
$rep_sql_min= mysql_fetch_array($res_sql_min);

mysql_free_result($res_sql_min);
$VAL_MIN=$rep_sql_min['VAL_MIN'];
echo ' Le minimum est= '.$VAL_MIN .'<br>';

$sql_max= "SELECT MAX(id) as VAL_MAX FROM mdl_log";
$res_sql_max=mysql_query($sql_max);
if($res_sql_max==FALSE)
{die(mysql_error());
mysql_close();}
$rep_sql_max= mysql_fetch_array($res_sql_max);

mysql_free_result($res_sql_max);
$VAL_MAX=$rep_sql_max['VAL_MAX'];
echo ' Le maximum est = '.$VAL_MAX  .'<br>';

$dx=$VAL_MAX-$VAL_MIN;
echo ' La difference est= '.$dx  .'<br>';

$dx1=$VAL_MAX-1000000;
echo ' adr_deb_mdl_log= '.$dx1  .'<br>';

                                /****************************************************/
                                            //creation des table

                               /****************************************************/
                                   

if ($dx>=1000000)                   
{
/*                         
$sql_create=" CREATE TABLE `moodle`.`mdl_log1` as (SELECT * FROM mdl_log WHERE id='9269739')";

$res1=mysql_query($sql_create);
if ($res1==FALSE)
{die(mysql_error());

mysql_close(); }                         

*/                                 /****************************************************/

                                   //Insertion des enregistrements dans les table

   
                                   /****************************************************/


$time=date('i');
$table_name="`moodle`.mdl_log".$time;

$sql_insert="CREATE TABLE $table_name as (SELECT* FROM `moodle`.`mdl_log`   WHERE `mdl_log`.`id` >=$VAL_MIN AND `mdl_log`.`id`<=$dx1)";
$res_sql_insert=mysql_query($sql_insert);
if ($res_sql_insert==FALSE)
{die(mysql_error());

mysql_close(); }                         

                              /****************************************************/

                                 //suppressiondes enregistrements de la table

                               /****************************************************/

include ('connection.php');
$db=mysql_select_db("moodle");
$sql_suppr="DELETE FROM `moodle`.`mdl_log` WHERE `mdl_log`.`id`>=$VAL_MIN AND `mdl_log`.`id`<=$dx1";
$res_sql_suppr=mysql_query($sql_suppr);
if ($res_sql_suppr==FALSE)

echo mysql_erreur();
}
mysql_close();             
                       
?>