Wikini

OptimisationSql

PagePrincipale :: DerniersChangements :: DerniersCommentaires :: ParametresUtilisateur :: Vous êtes ec2-54-198-94-76.compute-1.amazonaws.com

Optimisation du nombre de requetes SQL pour afficher une page par GouBs


Quelques explications sommaires
dans la version wikini actuelle, à chaque mot wiki correspond une requete SQL. Sur mon site perso, qui utilise un menu, une moyenne de 20 requetes correspondent à ces mots (sur un total d'environ 30). Les requetes associées à chaque mot Wiki permettent de savoir si la page associée à ce mot existe. L'idée est donc de remplacer ces 20 requetes par une seule !

Pour cela j'ai rajouté une fonction dans la class Wiki qui répertorie l'ensemble des mots Wiki présents dans la page (Header + body). L'ensemble de ces mots permet ensuite de construire une requete SQL du type "Select tag from pages where latest = 'Y' and ( tag = wikiMot1 or tag =wikiMot2 or ... )". Le résultat de la requete est utilisé pour mettre à jour un tableau Wiki du type "tab_mot_reference[wikiMot1]=true" pour chaque tag de page retourné.

La modification suivante intervient dans la fonction Link qui retourne un formatage de type page existante ou page à créer en fonction de la valeur du tableau précédent (if tab_mot_reference[wikiMot] then formatage page existante else formatage page à créer)
Pour que le tableau soit créé il faut bien sur appeler la fonction. J'ai mis cet appel dans la class Wiki au niveau de la fonction Method (appel du Handler). la derniere chose à faire est de déclarer le tableau dans l'entete de la class.

Seule la class Wiki est impactée par cette modification (dans le fichier wakka.php)


Remarques sur temps de traitement
Le principe adopté permet de réduire le nombre de requetes SQL mais on peut se poser la question de savoir si le temps de traitement rajouté pour remplir le tableau et celui correspondant à la requete SQL plus complexe ne sont pas pénalisant par rapport aux gains correspondant aux suppressions de requete.

Les premiers essais fait sur mon site perso montre que le temps global de traitement a baissé d'environ 15% et le pourcentage de ce temps consommé par les requetes SQL est passé d'environ 33% à 21%. Ces résultats ne sont biensur valables pour l'instant que dans le cadre de la configuration de mon site : environ 70 pages et une table page contenant environ 750 pages. Il serait interressant que d'autres puissent faire des essais sur un site + conséquent.

Pourquoi pas un tableau de résultats apres modif sous la forme ci-dessous mis à jour par chacun :
Nom Tps total % tps SQL Nb Pages Nb enreg table page
GouBs -15% -12% 70 750
?? ? ? ? ?


Pistes d'amélioration

Voir démo sur : Mon Site
--GouBs

code de la modification
<?php
/*  ----------------  déclaration du tableau  ---------------------- */
class Wiki
{
    var 
$tab_mots_wiki_definis = array(); /* ajout Goubs pour optimisation Rqt SQL */

/* ----------------- Ajout le la fonction --------------------------*/
/* Modification Goubs du 22/5/2004
    cette fonction permet de mettre dans une table la liste des mots wiki défini
   (c'est a dire ayant un enregistrement associé dans la table des pages
*/
function Ctrl_Mot_Wiki_Defini() {
// recherche de la liste des mots Wiki dans le Header et le body
$patterns "#".
    
"\b[A-Z][a-z_]+[A-Z,0-9][A-Za-z0-9_]*\b|"// mots wiki
    
"(?<=missingpage\">)[A-z0-9]+"// mots wiki forcés apparaisent pécédés de : missingpage">
    
"#"
    
$message $this->GetMessage(); //sauvegarde le message éventuel (sinon il est perdu !)
    
$contenu $this->Header().$this->Format($this->page["body"]);
    
$this->SetMessage($message); // restitue le message
    
$nb_mot preg_match_all ($patterns$contenu,$tab_mots_wiki);
    if (
$nb_mot 0){
        
// élimine les doublons du tableau
        
foreach ($tab_mots_wiki[0] as $value)
            
$tableau_mots[]=$value;
        
$tab_mots array_unique($tableau_mots);
        
$this->nb_mots_wiki count($tab_mots); /* pour test seulement */
        // construction d'une Rqt SQL à partir de ces mots
        
$Rqt_sql "Select tag from ".$this->config["table_prefix"].
            
"pages where latest = 'Y' and tag in(";
        foreach(
$tab_mots as $key=>$value
            
$Rqt_sql .= "'".$value."',";
        
$Rqt_sql .= "'')";
        
$Mots_definis $this->LoadAll($Rqt_sql);
        
// mise à jour d'un tableau avec les mots Wiki défini par une page
        
foreach ($Mots_definis as $Mot_defini)
            
$this->tab_mots_wiki_definis[$Mot_defini['tag']] = true;
    }
}
/* fin de la modification Goubs */

/* ---------------- dans la fonction Link ------------------------------------*/

// it's a Wiki link!
    
if ($_SESSION["linktracking"] && $track$this->TrackLinkTo($tag);
    
// modif Goubs pour optimiser le nombre de requete SQL
    //return ($this->LoadPage($tag) ? "<a href=\"".$this->href($method, $tag)."\">".str_replace('_',' ',$text)."</a>" : "<span class=\"missingpage\">".str_replace('_',' ',$text)."</span><a href=\"".$this->href("edit", $tag)."\">?</a>");
    
    
return (isset($this->tab_mots_wiki_definis[$tag]) ? "<a href=\"".$this->href($method$tag)."\">".str_replace '_',' ',$text)."</a>" "<span class=\"missingpage\">".str_replace('_',' ',$text)."</span><a href=\"".$this->href("edit"$tag)."\">?</a>");

/* ---------------- Appel de la fonction -----------------------------------*/
function Method($method) {
    if (!
$handler $this->page["handler"]) $handler "page";
    
$methodLocation $handler."/".$method.".php";
    
/* ******* ICI *********** */
    
$this->Ctrl_Mot_Wiki_Defini(); // ajout Goubs pour optimisation Rqt SQL
    
return $this->IncludeBuffered($methodLocation"<i>M&eacute;thode inconnue \"$methodLocation\"</i>"""$this->config["handler_path"]);
}
?>

Merci GarfieldFr. J'ai fait la modif comme tu l'indiquais en commentaire sur cette page (utiliser une clause WHERE du style : WHERE latest='Y' and tag in ('Page1','Page2?' ...) ). Je n'ai pas réussi à mesurer un gain de performance (pas d'outil de mesure assez précis) mais la solution est plus éléguante. --GoubS

Les outils en ligne de commande de MySQL permettent de voir le temp d'execution des requêtes ... regarde la doc de MySQL pour plus de précisions. --GarfieldFr

De toute façon à mon sens il y a forcément un gain de performances, sinon les listes ne serviraient à rien...

Il y a plusieurs choses qui posent problème dans ton code selon moi:
  1. l'entête et la page sont formattés entièrement une fois rien que pour récupérer les MotWiki, grosse perte de temps tout de même...
  2. tous les handlers n'ont pas besoin de formatter la page (notemment edit en mode édition, raw, revisions, referrers etc.), et donc n'ont pas besoin de savoir si ses liens existent ou non... pourtant tu les récupères quand même !
  3. tu ne tiens pas compte du fait qu'il peut, selon les handlers (par exemple diff, edit en mode aperçu etc.), y a avoir des liens qui ne font normalement pas partie de la page courante (dons mes exemples: un diff d'une page dans laquelle on aurait enlevé des liens, un aperçu d'une page où on est en train d'ajouter des liens). Dès lors ces mots apparaitront comme si la page en question n'existaire pas, alors qu'on n'en sait en fait rien... Pour palier cela il faudrait au moins stocker dans $tab_mots_wiki_definis la liste des mots qu'on n'a voulu récupérer mais qu'on n'a pas trouvés (en tout logique avec la valeur false...). Du coup, on est certain que la page existe (ou non) dans le cas où $tab_mots_wiki_definis['motWiki'] est défini, sinon il faut tout de même vérifier.
  4. il y a maintenant deux systèmes de mise en cache: ta gestion des MotWiki définis, et les pages mises en cache complètement via LoadPage...

Je vois trois autres solutions:
-- LordFarquaad


Voir mes commentaires sur SuggestionsRapiditeDeTraitement (fin de page). -- ProgFou

Pages ayant un lien vers la page courante :
ActionCalendrier
GarfieldFr
GoubS
LordFarquaad
SuggestionsRapiditeDeTraitement


PagesSuiviesParGoubs
Commentaires [Cacher commentaires/formulaire]