开发者

MySQL performance issue

I want to build a visual table where I can see the following things:

Team - Basketball stats about the team.

Number In League - The position that team is on each stat in the league.

League Average - The league average on each stat.

I have the following tables in my DB:

gamesstats: Have the stats on all games(what teams played and more) + link to stats table which holds all of the stat fields I want(2 links, one for the home team stat and one for the visitor team stat).

stats: Each row represents a game for one team(the stats such as 3 points attempts).

The situation is:

The "Team" row is easy to get and is fast(takes miliseconds).

The "League Average" row is easy and fast(same here).

The "Number In League" is however much slower(takes several seconds).

It is important for me that the creation won't take more than 5 seconds tops, but because I ask for the "Number In League" several times(3) in one page, it takes around 10-20 seconds.

The tables have around 100k entries.

Here is my implementation:

$p2pQuery = '100*avg(s.P2M)/avg(s.P2A)';
$p3pQuery = '100*avg(s.P3M)/avg(s.P3A)';
$ftpQuery = '100*avg(s.FTM)/avg(s.FTA)';
$effQuery = '(avg(s.TOT) + avg(s.AST) + avg(s.ST) + avg(s.PTS) + avg(s.P2M) +
              avg(s.P3M) + avg(s.FTM) + avg(s.RV) + avg(s.FV)) -
              (avg(s.TO) + avg(s.P3A) + avg(s.FTA) + avg(s.AG) + avg(s.CM))';

$whatWeWant = " avg(s.P2M) as P2M, avg(s.P2A) as P2A,  $p2pQuery as P2P,
                avg(s.P3M) as P3M, avg(s.P3A) as P3A,  $p3pQuery as P3P,
                avg(s.FTM) as FTM, avg(s.FTA) as FTA,  $ftpQuery as FTP,
                avg(s.OFFENSE) as OFFENSE, avg(s.DEF) as DEF, avg(s.TOT) as TOT, 
                avg(s.AST) as AST, avg(s.TO) as 'TO', avg(s.ST) as ST,
                avg(s.FV) as FV, avg(s.CM) as CM, avg(s.PTS) as PTS,
                $effQuery as EFF";

$allTeamsString = "SELECT t.ID as ID, $whatWeWant
                   FROM teams as t, gamesstats as gs, stats as s
                   WHERE gs.LeagueId = $ESCleague 
                   AND gs.SeasonStart = $ESCseason
                   AND ((gs.HomeTeamID = t.ID AND gs.VisitorStat = s.ID) 
                   OR (gs.VisitorTeamID = t.ID AND gs.HomeStat = s.ID))
                   GROUP BY t.ID";

$allTeamsQuery = MyQuery($al开发者_StackOverflow社区lTeamsString);
$allTeams = resultSet2RowArray($allTeamsQuery, true);

$stat2 = array();
$stat2['Flag'] = 'In League';
//$fields holds stuff like P2M AST EFF and such as you can see in $whatWeWant
foreach($fields as $field):
    $col = $field['colName'];
    $counter = 1;
    foreach($allTeams as $team)
        if($stat1[$col] < $team[$col])
            $counter++;
    $stat2[$col] = $counter;
endforeach;


If we keep in mind that AVG(x) = SUM(x) / count(x)
and that AVG(x) + AVG(y) = SUM(x+y) / count(x)

Then we can speed up this query using SUM() and COUNT().
However this will only work if there are no null rows!

$p2pQuery = '100*SUM(s.P2M)/SUM(s.P2A)'; 
$p3pQuery = '100*SUM(s.P3M)/SUM(s.P3A)';
$ftpQuery = '100*SUM(s.FTM)/SUM(s.FTA)';
$effQuery = '(SUM(s.TOT + s.AST +s.ST + s.PTS + s.P2M +
              s.P3M + s.FTM + s.RV + s.FV)) -
              (SUM(s.TO + s.P3A + s.FTA + s.AG + s.CM))';

$whatWeWant = " SUM(s.P2M) as P2M, SUM(s.P2A) as P2A,  $p2pQuery as P2P,
                SUM(s.P3M) as P3M, SUM(s.P3A) as P3A,  $p3pQuery as P3P,
                SUM(s.FTM) as FTM, SUM(s.FTA) as FTA,  $ftpQuery as FTP,
                SUM(s.OFFENSE) as OFFENSE, SUM(s.DEF) as DEF, SUM(s.TOT) as TOT, 
                SUM(s.AST) as AST, SUM(s.TO) as 'TO', SUM(s.ST) as ST,
                SUM(s.FV) as FV,  SUM(s.CM) as CM, SUM(s.PTS) as PTS,
                $effQuery as EFF";

$allTeamsString = "SELECT t.ID as ID, count(*) as divider, $whatWeWant
                   FROM teams as t
                   INNER JOIN gamesstats as gs 
                     ON (gs.HomeTeamID = t.ID) OR (gs.VisitorTeamID = t.ID)
                   INNER JOIN stats as s 
                     ON (gs.VisitorStat = s.ID) OR (gs.HomeStat = s.ID)
                   WHERE gs.LeagueId = '$ESCleague' 
                   AND gs.SeasonStart = '$ESCseason'
                   GROUP BY t.ID";

You can divide the result by field 'divider' if you need to in the php-code.
First see if the SQL-query runs any quicker.

Remarks

Don't use SQL '89 syntax, use SQL'92 instead
Please don't use an implicit where join. It's confusing and error prone. Use explicit SQL'92 join syntax instead. Then you can separate the join criteria from the filter criteria.
See the rewritten syntax in the answer.

Close that SQL-injection hole
And don't forget to enclose injected $vars in a query in ' single quotes if you don't want a SQL-injection attack to happen to you.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜