【问题标题】:MySQL/PHP Optimization - Poins based on client's dataMySQL/PHP 优化 - 基于客户数据的分数
【发布时间】:2016-06-26 06:24:14
【问题描述】:

我需要对此进行优化。 PHP:

$time_start = microtime(true); 
$servername = "127.0.0.1";
$username = "test";
$password = "test";
$dbname = "test";
//SQL prefix
$prefix = "test_";
$mysqli = new mysqli($servername, $username, $password, $dbname);

if ($mysqli->connect_errno) {
    echo "Failed to connect to MySQL: (" . $mysqli->connect_errno . ") " . $mysqli->connect_error;
}

$gamehighestrecords = array();

function GetHighestRecord($game) {
    global $gamehighestrecords, $mysqli, $prefix;

    if (isset($gamehighestrecords[$game])) {
        return $gamehighestrecords[$game];
    } else {
        $sql = $mysqli->query("SELECT rank FROM {$prefix}main_records WHERE game='{$game}' ORDER BY rank DESC LIMIT 1;");
        $res = $sql->fetch_row();
        $gamehighestrecords[$game] = $res[0];
        return $gamehighestrecords[$game];
    }
}

$sql = $mysqli->query("SELECT auth FROM test_player_data");
while ($res = $sql->fetch_array()) {
    $rsql = $mysqli->query("SELECT * FROM test_records WHERE auth='{$res["auth"]}'");

    $points = 0;

    while ($records = $rsql->fetch_array()) {
        $totalrank = GetHighestRecord($records["game"]);
        $rank = $records["rank"];

        if ($totalrank == 0) continue;
        if ($rank == 0) continue;

        $multiplier = 7500;
        $points += (((1 - ($rank / $totalrank))) * $multiplier);
    }

    $mysqli->query("UPDATE test_player_data SET points={$points} WHERE auth='{$res["auth"]}'");
}

$time_end = microtime(true);
$execution_time = ($time_end - $time_start);
//execution time of the script
echo '<b>Total Execution Time:</b> '.$execution_time.' Seconds';

和mysql结构:

== Table structure for table test_player_data

|------
|Column|Type|Null|Default
|------
|//**id**//|int(11)|No|
|**auth**|varchar(32)|No|
|points|float|No|
|rank|int(11)|No|

.

== Table structure for table test_main_records

|------
|Column|Type|Null|Default
|------
|//**id**//|int(11)|No|
|**auth**|varchar(32)|No|
|**game**|varchar(128)|No|
|time|float|No|
|rank|int(11)|No|

test_player_data 有 ~3k 记录,test_main_records 有 ~6k 记录。 执行 php 脚本大约需要 0.7 秒(总执行时间:0.6869421005249 秒)。表格将变得更大,0.7 秒不会削减它。平均而言,每分钟将输入/更改一条新记录。然后我需要重新计算分数。我正在考虑只更新那些在那个“游戏”中有更新的记录,但以后会有成千上万的记录。

id 是主要的,auth/game 是唯一的。

我希望我在这里说得通。

另外,我知道我的代码很糟糕。这只是“概念证明”。

【问题讨论】:

  • 我投票结束这个问题,因为它是代码审查。
  • 可以通过在 while 循环之前启动事务并在 while 循环之后提交来加快速度。
  • 并且您可以将 while 循环上方和内部的 2 个 SELECT 循环组合成 1 个单个查询,从而删除整个查询循环,例如 SELECT * FROM test_records INNER JOIN test_player_data ON test_records.auth=test_player_data.auth
  • 并且 GetHighestRecord 函数可以通过使用带有绑定参数的准备好的语句进行优化,这可能是一次操作 (static $preparedStatement=false;if($preparedStatement===false){/*first-time-run make a prepared statement and bind paramters*/}),而不是每次缓存未命中时生成一个全新的查询(感谢制作缓存)

标签: php mysql sql optimization


【解决方案1】:

提供SHOW CREATE TABLE

第一次查询需要INDEX(game, rank)

考虑有多个相同的表。

在 SQL 中循环,而不是 PHP:改变这个

SELECT auth FROM test_player_data
while
    SELECT * FROM test_records WHERE auth='{$res["auth"]}'

到这里:

SELECT r.*
    FROM test_player_data AS p
    JOIN test_records AS r  ON r.auth=p.auth
while

但是,为什么还要碰test_player_data

SELECT r.*
    FROM test_records AS r
while

在那之后,也许我们可以考虑将其他查询折叠到其中?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-01-23
    • 2013-12-13
    • 1970-01-01
    • 1970-01-01
    • 2017-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多