在循环MySQL时修复性能问题导致PHP

时间:2014-08-01 03:26:06

标签: php mysql mysqli

我正在开发一款虚拟游戏板风格的游戏,玩家可以在棋盘的某个区域获得积分。 (现在就把它放在我身上,因为我只是做这个爱好所以我可能会以最坏的方式做到这一点)

我有3张桌子。一个存储所有玩家信息(例如,id,屏幕名称)。第二个存储所有区域信息(例如,id,x,y),第三个存储每个玩家在每个区域中具有多少点(例如,id,playerid,areaid,points)。为了创建一个"排行榜"我循环遍历所有玩家,然后在该循​​环中我也循环遍历所有区域,然后最终在第二个循环中,我得到该区域的领导者,看看它是否与当前玩家匹配第一个循环,如果是这样我增加一个计数器,然后将其存储到一个数组中。 (参见下面的代码并附上一些评论)

我研究了MySQL缓存,但我无法访问许多服务器选项,并且希望尽可能多地保留结果,因此缓存可能不是正确的方法。

我的问题是我是否正确地做到了这一点。目前只有大约10名球员,大约。 500个地区。我发现下面的脚本大约需要5-8秒才能运行。可能会有数百万个区域,因此如此长时间的处理延迟可能是灾难性的(无论如何对于排行榜)。我是否采用正确的方式,和/或有更好的方法吗?

<?php
    $leaders = array();

    //Loop through all the players
    $sql = "SELECT * FROM players";
    $result = mysqli_query($con, $sql) or die(mysqli_error($con));
    while ($row = mysqli_fetch_array($result)) {
        //save player information into variables
        $playerId = $row['id'];
        $playerScreenName = $row['screenname'];

        //Reset the area counter
        $AreaCount = 0;
        $leader = array();

        //Loop through all areas
        $sql2 = "SELECT * FROM areas";
        $result2 = mysqli_query($con, $sql2) or die(mysqli_error($con));
        while ($row2 = mysqli_fetch_array($result2)) {
            $areaId = $row2['id'];

            //Get the player with the most points in that area
            $sql3 = "SELECT * FROM points WHERE areaid='$areaId' ORDER BY totalpoints DESC LIMIT 1";
            $result3 = mysqli_query($con, $sql3) or die(mysqli_error($con));
            while ($row3 = mysqli_fetch_array($result3)) {
                $leaderOfArea = $row3['playerid'];

                //See if the leader of the area is the same player we are looping through
                if ($playerId == $leaderOfArea) {
                    //if it is, then increment the counter
                    $AreaCount++;
                }
            }
        }
        //Store the leader information into an array to be output later
        $leader['screenname'] = $playerScreenName;
        $leader['areacount'] = $AreaCount;

        $leaders[] = $leader;
    }

    // sort leaders by score
    usort($leaders, 'compare_areacount');
?>

2 个答案:

答案 0 :(得分:0)

打开数据库连接会产生开销,当你在循环中执行它时,会加剧问题(然后当你在其中添加一个循环时,你会让它变得更糟)。而是使用Join或Subquery将其重组为一个查询。

This post has some specifics.

答案 1 :(得分:0)

我认为这段代码可以提供帮助。您可能必须使用所需的适当列名更改sql查询。

<?php

$leaders = array();

//Loop through all the players
$sql = "SELECT * FROM players";
$result = mysqli_query($con, $sql) or die(mysqli_error($con));

$players = array();
while ($row = mysqli_fetch_array($result)) {
    //save player information into variables
    $players[$row['id']] = array($row['screenname'], 0);
    // number 0 will be the count of how many times this player is the leader
}

$sql = "SELECT Area.id, Area.name, (SELECT Pts.playerid FROM `points`"
    . " AS Pts WHERE Pts.areaid=Area.id ORDER BY totalpoints"
    . " DESC LIMIT 1) AS `leader_id` FROM `areas` AS Area";
$result = mysqli_query($con, $sql) or die(mysqli_error($con));

$areas = array();
while ($row = mysqli_fetch_row($result)) {
    $areas[$row[0]] = $row;

    // $row[2] will contain leader_id
    // index 1 corresponds to the second element in player values array
    $players[$row[2]][1]++;
}

// now if you want to print:
foreach ($areas as $area_id => $area) {
    echo "Area id: " . $area_id . ", name: " . $area[1] . ", leader_id: " . $area[2] . "<br /><br />";
}

foreach ($players as $player_id => $player) {
    echo "Player id: " . $player_id . ", name: " . $player[0] . ", No of areas this player is a leader of: " . $player[1] . "<br /><br />";
}