Witam
Ponizej przedstawie (o po krotce opisze) pewna funkcje. Powoduje ona przeliczenie punktow zdobywanych przez graczy w cos na wzor ligi typerow.
mamy zatem nastepujace elementy 'ukladanki'
- gracze
- rodzaj ligi
- numer kolejki
- zestawienie meczow
- wyniki wytypowanwe przez graczy
- punkty
<?php
function calculateWeekScore(){
$week_id = $_REQUEST["week"]; //id kolejki/tygodnia rozgrywek
$comp_id = $_REQUEST["comp_id"]; //id rodzaju ligi
$competition = new Competition($comp_id);
$competition_type = new CompetitionType($competition->comp_type_id);
// tworze tablice wszystkich graczy typujacych w danej lidze
$qry = "SELECT sysuser.id as id FROM sysuser, sysuser_competition WHERE sysuser_competition.competition_id = $comp_id AND sysuser_competition.sysuser_id = sysuser.id ORDER BY id ASC";
$sth = $dbh->prepare($qry);
$sth->execute();
while ($row = $sth->fetch()) {
$users[] = $row;
}
// tworze tablice meczow w danej kolejce
$qry = "SELECT * FROM fixture WHERE competition_id = $comp_id AND week_id = $week_id ORDER BY id ASC";
$sth = $dbh->prepare($qry);
$sth->execute();
while ($row = $sth->fetch()) {
$fixtures[] = $row;
}
//loopuje tablice graczy
foreach ($users as $user){
$total_score = 0;
$no_of_predictions = 0;
//dla kazdego gracza sprawdzam, czy wytypowal wynik (prediction) na dany mecz kolejki
foreach ($fixtures as $fixture){
$qry = "SELECT * FROM predictions WHERE fixture_id = ".$fixture["id"]." AND user_id = ".$user["id"]."";
$sth = $dbh->prepare($qry);
$sth->execute();
$row = $sth->fetch();
if($sth->rowCount() > 0){
$no_of_predictions++;
}
// jesli gracz wytypowal wynik, pobieram typ (1, X lub 2) i margines zwyciestwa (jaka iloscia bramek wygrala zwyciezka druzyna)
$prediction = $row["prediction"];
$prediction_id = $row["id"];
$margin = $row["margin"];
//porownuje typy w prawdziwymi wynikami
if($fixture["result"] == $prediction){
if($fixture["result"] == "X"){
$score = $competition_type->draw_score; //jesli remis - przypisuje ilosc punktow jaka w danym typie ligi przysluguje za celne wytypowanie remisu
}elseif($fixture["result"] != ""){
$score = $competition_type->winner_score; //jesli zwyciestwo - przypisuje ilosc punktow jaka w danym typie ligi przysluguje za celne wytypowanie zwyciezcy
$margin_accuracy = Abs($fixture["margin"] - $margin); $margin_score = getMarginScore($margin_accuracy, $comp_id); // przypisuje punkty za dokladnosc trafienia wyniku (funkcja getMarginScore wysyla zapytanie do bazy - sprawdzana jest jedna tablica w bazie)
if(!$margin_score){
$margin_score = 0;
}
if(!$score){
$score = 0;
}
}
$overal_score = $score + $margin_score;
$total_score = $total_score + $overal_score;
}else{
$overal_score = 0;
}
// updatuje tablice typow dodajac ilosc punktow jaka w sumie zdobyl gracz za wytypowanie meczu
$qry = "UPDATE predictions SET score = $overal_score WHERE id = $prediction_id";
$sth = $dbh->prepare($qry);
$sth->execute();
$margin_score = 0;
$score = 0;
$margin_accuracy = 0;
} //koniec petli porownujacej typy z wynikami (tablica fixtures[])
$user_id = $user["id"];
if($no_of_predictions == 0){
$no_prediction_users .= "$user_id,";
}else{
//jesli kolejka nie jest zakonczona, dodaje do tabeli sysuser_week_score calkowita ilosc punktow zdobytych za wytypowanie wszystkich meczow w danej kolejce.
if(!isCompleted($week_id)){
$qry = "INSERT INTO sysuser_week_score (sysuser_id, week_id, competition_id, score) VALUES ('$user_id', '$week_id', '$comp_id', '$total_score')";
$sth = $dbh->prepare($qry);
$sth->execute();
// jesli jest zakonczona, updatuje istniejacy wpis (mowiac 'zakonczona' mam na mysli, ze admin dokonal juz wczesniej kalkulacji wynikow przynajmniej raz)
}else{
$qry = "UPDATE sysuser_week_score SET score = '$total_score' WHERE sysuser_id = $user_id AND competition_id = $comp_id AND week_id = $week_id";
$sth = $dbh->prepare($qry);
$sth->execute();
}
// w celu updatowania sumy punktow zebranych w calej grze, na przestrzeni wszystkich kolejek, pobieram sume punktow zdobytych w tej i wszystkich poprzednich kolejkach. Funkcja getAllWeeksScore wysyla proste zapytanie do jednej tablicy (sysuser_week_score)
$all_weeks_score = getAllWeeksScore($user_id, $comp_id);
// update tablicy sysuser_score zawierajacej pole z suma punktow zdobytych w calej grze. Tu w zasadzie powinienem zamienic delete i insert na jedno zapytanie update
$qry = "DELETE FROM sysuser_score WHERE sysuser_id = $user_id AND competition_id = $comp_id";
$sth = $dbh->prepare($qry);
$sth->execute();
$qry = "INSERT INTO sysuser_score (sysuser_id, competition_id, score, last_week_score) VALUES ('$user_id', '$comp_id', '$all_weeks_score', '$total_score')";
$sth = $dbh->prepare($qry);
$sth->execute();
}
}
// gracze, ktorzy nie dali zadnych typow w danej kolejce, otrzymuja usredniona ilosc punktow innych graczy (to nie moj wymysl, ino klienta :) )
//zatem, getAvgWeekScore wykonuje zapytanie na jednej tablicy sumujac punkty poszczegolnych graczy, zdobytych w bierzacej kolejce. Funkcja zwraca ilosc tych punktow podzielona oczywiscie przez ilosc graczy
$avg_score = getAvgWeekScore($comp_id, $week_id);
//wszyscy ci gracze, ktorzy nie wzieli udzialu w typowaniu w danym tygodniu, zostali wczesniej wpisani do zmiennej $no_prediction_users (string z id graczy po przecinkach)
// funkcja updateUsersAvgScore 'exploduje' ta zmienna wyluskujac id graczy, a nastepnie odpala foreach dla kazdego gracza. W petli tej odbywa sie dokladnie to samo co mialo miejsce dla graczy, ktorzy typowali... tyle, ze tym razem nie ma porownania typow z wynikami. Odbywa sie zatem dodanie sredniej ilosci punktow do tablicy sysuser_week_score (punktacja w kolejnych kolejkach), zsumowanie punktow z calej gry (getAllWeeksScore) i wpisanie ich do tablicy z punktami (sysuser_score)
updateUsersAvgScore($no_prediction_users, $avg_score, $comp_id, $week_id);
// zamkniecie kolejki
$qry = "UPDATE week SET completed = 1 WHERE id = $week_id;";
$sth = $dbh->prepare($qry);
$sth->execute();
}
?>
Problem polega na tym, ze przy okolo 300 graczach, cala operacja trwa koszmarnie dlugo (2-3 minuty zanim strona zostanie odswiezona). Potrzebuje porady w jaki sposob zoptymalizowac funkcje aby dzialala szybciej. Jesli cos jest nie jasne albo potrzebujecie wiecej informacji, pytajcie...
Dzieki z gory za pomoc
Ten post edytował soska66 16.02.2009, 15:42:27