RE: [PHP&MySQL] Optimisation de statistiques et UPDATE - pascal - 17-11-2008
et en faisant SUM / GROUP BY id_joueur ?
A+
Pascal
RE: [PHP&MySQL] Optimisation de statistiques et UPDATE - Cartman34 - 17-11-2008
Ca arrange pas mon problème pour les planètes et lunes et je pourrais l'appliquer aux utilisateurs par contre.
je pourrais avoir une seule requete qui calcule la somme des points des planètes et lunes pour les mettre dans la table des joueurs, un peu comme je faisais avant (mais à chaque actua...) mais je ne pourrais plus avoir de rangs.
RE: [PHP&MySQL] Optimisation de statistiques et UPDATE - pascal - 17-11-2008
si tu expliques un peu plus et si tu montres un peu comment tu calcules les points pour les différents éléments...
ha mais je l'ai déjà dit ça
sans la structure de données, on ne peut pas t'aider plus que ça.
A+
Pascal
RE: [PHP&MySQL] Optimisation de statistiques et UPDATE - Cartman34 - 17-11-2008
Comme tu voudras mais si tu comprends quelque chose sans connaitre toutes les fonctions et variables, je te nomme "Dieu".
Ce script est sous licence Creative Commons Paternité-Pas d'Utilisation Commerciale-Partage des Conditions Initiales à l'Identique 2.0 France:
Code PHP : <?php //stats_update.php By IGstaff
/*
Fichier de mise à jour automatique sans affichage des résultat.
Les tableaux suivants doivent être définis et complétés:
- $DBTables
- $PointsTypes
*/
function countbylvl($level,$pricelist) {
$points = 0;
$points = ($pricelist["metal"]+$pricelist["crystal"]+$pricelist["deuterium"])*(1+$pricelist["factor"]*(1-pow($pricelist["factor"],$level))/(1-$pricelist["factor"]));
$points /= 1000;
return $points;
}
function countbynb($nb,$pricelist) {
$resultat = $nb*($pricelist["metal"] + $pricelist["crystal"] + $pricelist["deuterium"]);
$resultat /= 1000;
return $resultat;
}
//Mise à jour de la config
//Celle ci a été mise avant car si elle dure, elle risquerait de se répéter en cas de rechargement de la page.
$time = ( defined("TIME") ) ? TIME : time();
doquery("UPDATE {{table}} SET config_value={$time} WHERE config_name='stats' ","config");
$DBTablesF = array_big_flip($DBTables);
$Universe = $Points = $Ranks = array();
foreach($DBTables["BinSyst"] AS $BinSystTableName) {
$AllBinSystSQL = doquery("SELECT * FROM {{table}}", $BinSystTableName);
while( $AllBinSystArr = mysql_fetch_assoc($AllBinSystSQL) ) {
$Universe[$AllBinSystArr["id_owner"]][$BinSystTableName][$AllBinSystArr["id"]] = $AllBinSystArr;
}
}
text("Mise à jour des points !");
$AllUsersSQL = doquery("SELECT * FROM {{table}}","users");
while( $AllUsersArr = mysql_fetch_assoc($AllUsersSQL) ) {
$UserID = $AllUsersArr["id"];
if( !empty($Universe[$UserID]) ) { //Si le joueur a des planètes/lunes
//Initialisation des points
$points = array();
$Universe[$UserID][$DBTables["User"]] = $AllUsersArr;
$UserArr = $Universe[$UserID];
unset($AllUsersArr);
//Enregistrement des points actuels comme anciens.
foreach($PointsTypes["User"] as $PointsTypeName) {
$UserArr[$DBTables["User"]]["points_{$PointsTypeName}_old"] = $UserArr[$DBTables["User"]]["points_{$PointsTypeName}_cur"];
}
///Initialisation des points actuels à 0.
foreach($DBTablesF as $DBTableName => $DBTablesObj) {
if( !empty($UserArr[$DBTableName]) ) {
if( is_array($DBTables[$DBTablesObj]) ) {
foreach($UserArr[$DBTableName] as &$UserObjArr) {
foreach($PointsTypes[$DBTablesObj] as $PointsTypeName) {
$UserObjArr["points_{$PointsTypeName}_cur"] = 0;
}
}
} else {
foreach($PointsTypes[$DBTablesObj] as $PointsTypeName) {
$UserArr[$DBTableName]["points_{$PointsTypeName}_cur"] = 0;
}
}
}
}
//On liste les différents objets du système binaire (planète et lune)
foreach($DBTables["BinSyst"] AS $BinSystTableID => $BinSystTableName) {
if( !empty($UserArr[$BinSystTableName]) ) {
$UserBinSyst = $UserArr[$BinSystTableName];
foreach($UserBinSyst as &$PlanetArr) { //Boucle des planetes - Début
//Ajout des points de Batiments
foreach($reslist[$BinSystTableID]["build"] as $a) {
$level = $PlanetArr[$resource[$a]];
if( !empty($level) && $level >0 ) {
$PlanetArr["points_bui_cur"] += countbylvl($level,$pricelist[$a]);
}
}
$PlanetFleetsFlying = array();
$PlanetFleetsSQL = doquery("SELECT fleet_array FROM {{table}} WHERE fleet_start_galaxy={$PlanetArr["galaxy"]} AND fleet_start_system={$PlanetArr["system"]} AND fleet_start_planet={$PlanetArr["planet"]}", "fleets");
while( $PlanetFleetsArr = mysql_fetch_assoc($PlanetFleetsSQL) ) {
$PlanetFleetsFlying = array_add_values($PlanetFleetsFlying, strtoarr($PlanetFleetsArr["fleet_array"]));
}
foreach($reslist[$BinSystTableID]["fleet"] as $a) { //Ajout des points de Flotte
$nb = $PlanetArr[$resource[$a]] + ( ( empty($PlanetFleetsFlying[$a]) ) ? 0 : $PlanetFleetsFlying[$a] );
if( !empty($nb) && $nb >0 ) {
$PlanetArr["points_fle_cur"] += countbynb($nb, $pricelist[$a]);
}
}
foreach($reslist[$BinSystTableID]["defense"] as $a) { //Ajout des points de Défense
$nb = $PlanetArr[$resource[$a]];
if( !empty($nb) && $nb >0 ) {
$PlanetArr["points_def_cur"] += countbynb($nb, $pricelist[$a]);
}
}
//Ajout dans les points totaux de l'utilisateur
$UserArr[$DBTables["User"]]["points_bui_cur"] += $PlanetArr["points_bui_cur"];
$UserArr[$DBTables["User"]]["points_fle_cur"] += $PlanetArr["points_fle_cur"];
$UserArr[$DBTables["User"]]["points_def_cur"] += $PlanetArr["points_def_cur"];
//Enregistrement dans la base SQL - Planète
doquery("UPDATE {{table}} SET points_bui_cur={$PlanetArr["points_bui_cur"]}, points_fle_cur={$PlanetArr["points_fle_cur"]},
points_def_cur={$PlanetArr["points_def_cur"]} WHERE id={$PlanetArr["id"]} LIMIT 1", $type_tab[$BinSystTableID]);
}
}
}
foreach($reslist[0]["tech"] as $a) { //Ajout des points de Technologies
$level = $UserArr[$DBTables["User"]][$resource[$a]];
if(!empty($level) && $level >0) {
$UserArr[$DBTables["User"]]["points_sea_cur"] += countbylvl($level,$pricelist[$a]);
}
}
if( !$UserArr[$DBTables["User"]]["authlevel"] || !empty($game_config["admin_instats"]) ) { //On exclue les admin du classement.
$Points["total"][$UserID] = $UserArr[$DBTables["User"]]["points_sea_cur"] + $UserArr[$DBTables["User"]]["points_bui_cur"]
+ $UserArr[$DBTables["User"]]["points_fle_cur"] + $UserArr[$DBTables["User"]]["points_def_cur"];
$Points["sea"][$UserID] = $UserArr[$DBTables["User"]]["points_sea_cur"];
$Points["bui"][$UserID] = $UserArr[$DBTables["User"]]["points_bui_cur"];
$Points["fle"][$UserID] = $UserArr[$DBTables["User"]]["points_fle_cur"];
$Points["def"][$UserID] = $UserArr[$DBTables["User"]]["points_def_cur"];
}
$Universe[$UserID] = $UserArr;
}
}
unset($UserArr);
$Points = array_map("re_arsort", $Points);
foreach($Points as $PointType => $PointUsers) {
$Rank = 0;
foreach($PointUsers as $PointUserID => $PointUserNb) {
$Rank++;
$Ranks[$PointUserID][$PointType] = $Rank;
}
}
foreach($Ranks as $RankUserID => $RankTypes) {
$UserQuery = "";
foreach($RankTypes as $RankType => $RankNb) {
$UserQuery .= var_add($UserQuery, ",")."`points_{$RankType}_old`=points_{$RankType}_cur, `points_{$RankType}_cur`={$Points[$RankType][$RankUserID]},
`rank_{$RankType}_old`=rank_{$RankType}_cur, `rank_{$RankType}_cur`={$RankNb}";
}
doquery("UPDATE {{table}} SET {$UserQuery} WHERE `id`={$RankUserID} ", "users");
}
//Suppression du cache des statistiques
cache_delete_all("stats");
/* 04/11/08
ALTER TABLE `ugml_users` DROP `rank`,
DROP `rank_old`,
CHANGE `points_sea` `points_sea_cur` BIGINT( 15 ) UNSIGNED NOT NULL DEFAULT '0',
CHANGE `points_bui` `points_bui_cur` BIGINT( 15 ) UNSIGNED NOT NULL DEFAULT '0',
CHANGE `points_fle` `points_fle_cur` BIGINT( 15 ) UNSIGNED NOT NULL DEFAULT '0',
CHANGE `points_def` `points_def_cur` BIGINT( 15 ) UNSIGNED NOT NULL DEFAULT '0',
ADD `points_total_cur` BIGINT( 15 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `deleteaccount`,
ADD `points_total_old` BIGINT( 15 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `points_def_cur`,
ADD `total_rank_cur` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `points_def_old` ,
ADD `sea_rank_cur` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `total_rank_cur` ,
ADD `bui_rank_cur` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `sea_rank_cur` ,
ADD `fle_rank_cur` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `bui_rank_cur` ,
ADD `def_rank_cur` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `fle_rank_cur` ,
ADD `total_rank_old` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `def_rank_cur` ,
ADD `sea_rank_old` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `total_rank_old` ,
ADD `bui_rank_old` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `sea_rank_old` ,
ADD `fle_rank_old` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `bui_rank_old` ,
ADD `def_rank_old` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0' AFTER `fle_rank_old` ;
ALTER TABLE `ugml_planets`
DROP `points_bui_old`,
DROP `points_fle_old`,
DROP `points_def_old`,
CHANGE `points_bui` `points_bui_cur` BIGINT( 15 ) UNSIGNED NOT NULL DEFAULT '0',
CHANGE `points_fle` `points_fle_cur` BIGINT( 15 ) UNSIGNED NOT NULL DEFAULT '0',
CHANGE `points_def` `points_def_cur` BIGINT( 15 ) UNSIGNED NOT NULL DEFAULT '0';
ALTER TABLE `ugml_lunas`
DROP `points_bui_old`,
DROP `points_fle_old`,
DROP `points_def_old`,
CHANGE `points_bui` `points_bui_cur` BIGINT( 15 ) UNSIGNED NOT NULL DEFAULT '0',
CHANGE `points_fle` `points_fle_cur` BIGINT( 15 ) UNSIGNED NOT NULL DEFAULT '0',
CHANGE `points_def` `points_def_cur` BIGINT( 15 ) UNSIGNED NOT NULL DEFAULT '0';
ALTER TABLE `ugml_users` CHANGE `total_rank_cur` `rank_total_cur` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0',
CHANGE `sea_rank_cur` `rank_sea_cur` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0',
CHANGE `bui_rank_cur` `rank_bui_cur` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0',
CHANGE `fle_rank_cur` `rank_fle_cur` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0',
CHANGE `def_rank_cur` `rank_def_cur` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0',
CHANGE `total_rank_old` `rank_total_old` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0',
CHANGE `sea_rank_old` `rank_sea_old` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0',
CHANGE `bui_rank_old` `rank_bui_old` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0',
CHANGE `fle_rank_old` `rank_fle_old` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0',
CHANGE `def_rank_old` `rank_def_old` INT( 5 ) UNSIGNED NOT NULL DEFAULT '0';
*/
?>
Les requêtes SQL à la fin ne vous permettent PAS de recréer les tables utilisées mais servaient à modifier les anciennes tables afin d'être compatible avec ce système.
Elles peuvent vous aider à comprendre le script cependant.
RE: [PHP&MySQL] Optimisation de statistiques et UPDATE - pascal - 18-11-2008
je reste sur les jointures, avec des updates par lots, genre :
- mettre à jour les points pour toutes les planetes et lunes
- mettre à jour les points pour tous les joueurs
pour ça, il faudrait passer par des jointures, sur l'id joueur. le modele de données avec les relations manque. Il faudrait peut être créeer des tables en plus pour stocker ces points.
A+
Pascal
RE: [PHP&MySQL] Optimisation de statistiques et UPDATE - Cartman34 - 18-11-2008
Tu voudrais faire le calcul via MySQL ? (extremement difficile et lourd)
Ou Tu voudrais que je fasse un enregistrement des nombres obtenus avec une grosse grosse jointure ?
Il peut y avoir facilement 10 planètes par joueurs et jusqu'au meme nombre de lune.
Je souhaite rester sur ce modèle. (je n'ai absolument pas envie de relancer le débat)
Tu crois qu'un UPDATE avec une grosse jointure serait plus rapide ?
RE: [PHP&MySQL] Optimisation de statistiques et UPDATE - pascal - 18-11-2008
je pense que c'est une piste, il faudrait benchmarker tout ça.
en tous cas, ça ferait moins de requêtes, mais des requêtes plus lourdes.
A+
Pascal
RE: [PHP&MySQL] Optimisation de statistiques et UPDATE - Cartman34 - 18-11-2008
Je suis en train de le faire. Merci.
EDIT: Voici les résultats Pour 6 joueurs et 8 planètes/lunes:
- Avec une jointure:
Temps Moyen d'exécution(sec): 0.00870922851563
stats_update.join.php (Taille : 10,11 Ko / Téléchargements : 3)
- Avec plusieurs requetes:
Temps Moyen d'exécution(sec): 0.00744750976562
stats_update.more.php (Taille : 9,39 Ko / Téléchargements : 1)
Je joins les 2 scripts
RE: [PHP&MySQL] Optimisation de statistiques et UPDATE - zeppelin - 19-11-2008
A mon humble avis c'est la conception qui ne joue pas, niveau code pas grand chose à dire, ci ce n'est que ton code est très peu agréable à lire, peu clair, pas hyper bien structuré... Mais la n'est pas la question! Avec des objects tu pourrais probablement gagner un peu de temps d'exécution.
Mais si tu veux vraiment remédier au problème du gros update, ben... tu fais que c'est pas un gros mais pleins de petits XD
Je m'explique: Au lieu d'actualiser tous les joueurs chaques 30 min. ou je ne sais quoi, tu les actualises un par un, et ceci seulement quand tu en as besoin!
Sur mon jeu j'ai un problème encore plus complexe, car je gère des troupes en temps réel ect. La solution est celle la: Tu écris une function à laquelle tu passe le joueur en param, et ta fonction update uniquement ce joueur. Ne te reste plus qu'a charger cette fonction au bons endroits : vue d'ensemble ou mon classement est affiché par exemple, fiche des autres joueurs que je visite ainsi de suite!
J'espère avoir pu t'aider... bonne chance ;-)
ps. en POO tu aurais 10 fois plus de facilitées, je t'encourage vivement à t'y coller, tu as une bonne concéption des multis arrays d'après ce que j'ai vu, la POO ne devrait plus être trop difficile dès lors niveau logique ;-)
RE: [PHP&MySQL] Optimisation de statistiques et UPDATE - Cartman34 - 19-11-2008
T'inquiète pas Zeppelin, je gère la POO mais dans le jeu, il n'y a aucune classe (ou presque) à la base et je vais pas m'aventurer à en ajouter comme ça.
De plus, il y aurait soit trop d'objet et je devrais en définir des masses, soit ca reviendrait un peu au même ici.
Le mieux serait de recoder tout le jeu...mais je doute que tu saches la masse que c'est, c'est pas un Ogamelike pour rien.
A la base, les points s'ajoutait au fur et à mesure des constructions etc... mais c'était un vrai calvaire car il y avait une montagnes de faille et ca devenait lourd tout le temps.
Quant à le faire au moment opportun...s'il n'y a pas de joueurs, les statistiques ne se mettent pas à jour et s'il y en a, ils vont tout le temps les voir. Donc je dois régulièrement actualiser (c'est réglé par défaut à 1 heure normalement et passé à 24heures de délai à cause des lourdeurs mais c'est configurable :p)
Si tu remarques bien, tout est organisé dans ce script (ca fait un peu prétentieux...) et les boucles sont à la pelle (ou à l'appel).
En soit, ce script est extrêmement rapide mais les lenteurs viennent surtout des requêtes.
Enfin, je pourrais surement y gagner beaucoup en sachant exactement ce qui est plus rapide que ce que j'ai mis en détails.
il est vrai qu'il n'est pas très commenté et estimez vous heureux d'avoir des commentaires...lol
|