我需要一些帮助来改进当前代码。我有一个巨大的数组(其中约有20,000个对象)。该数组如下所示:
Array ( [0] => Player Object ( [name] => Aaron Flash [level] => 16 [vocation] => Knight [world] => Amera [time] => 900000 [online] => 1 ) [1] => Player Object ( [name] => Abdala da Celulose [level] => 135 [vocation] => Master Sorcerer [world] => Amera [time] => 900000 [online] => 1 ) [2] => Player Object ( [name] => Ahmudi Segarant [level] => 87 [vocation] => Elite Knight [world] => Amera [time] => 900000 [online] => 1 ) [3] => Player Object ( [name] => Alaskyano [level] => 200 [vocation] => Royal Paladin [world] => Amera [time] => 900000 [online] => 1 ) [4] => Player Object ( [name] => Aleechoito [level] => 22 [vocation] => Knight [world] => Amera [time] => 900000 [online] => 1 )
依此类推…总共约有20,000个玩家对象。
现在,我要将它们全部插入到我的数据库中。我想找到一种不让所有玩家陷入困境的方法。它导致了很多性能问题,并且几乎使我的计算机丧命。我想一次完成一个查询。
但是,如何获得播放器对象的属性,例如每个对象的“名称”,“级别”和“职业”,而又不循环它们呢?
这是我的代码如下所示:
// Insert player list to database $sql = $db->prepare("INSERT INTO players (name, level, vocation, world, month, today, online) VALUES (:name, :level, :vocation, :world, :time, :time, :online) ON DUPLICATE KEY UPDATE level = :level, vocation = :vocation, world = :world, month = month + :time, today = today + :time, online = :online"); foreach ($players as $player) { $query = $sql->execute([ ":name" => $player->name, ":level" => $player->level, ":vocation" => $player->vocation, ":world" => $player->world, ":time" => $player->time, ":online" => $player->online ]); }
因为现在在底部的那个foreach上,它正在遍历我数组中的20,000个播放器对象,并获取它们的名称/级别/职业/世界等。
有一个更好的方法吗?我的方式不可能是最好的解决方案。我可以听到我的PC正在超负荷工作,并且感觉好像即将崩溃。
尽管我仍然怀疑事务和/或批处理插入是否是解决资源使用问题的可行解决方案,但是与准备像Dave所建议的那样的大量语句相比,它们仍然是更好的解决方案。
试一试,看看它们是否有帮助。
以下假定PDO的错误处理模式设置为引发异常。例如:$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);如果由于某种原因不能使用Exception模式,则需要检查execute()每次返回的值并抛出自己的Exception。
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
execute()
单笔交易:
$sql = $db->prepare("INSERT INTO players (name, level, vocation, world, month, today, online) VALUES (:name, :level, :vocation, :world, :time, :time, :online) ON DUPLICATE KEY UPDATE level = :level, vocation = :vocation, world = :world, month = month + :time, today = today + :time, online = :online"); $db->beginTransaction(); try { foreach ($players as $player) { $sql->execute([ ":name" => $player->name, ":level" => $player->level, ":vocation" => $player->vocation, ":world" => $player->world, ":time" => $player->time, ":online" => $player->online ]); } $db->commit(); } catch( PDOException $e ) { $db->rollBack(); // at this point you would want to implement some sort of error handling // or potentially re-throw the exception to be handled at a higher layer }
批量交易:
$batch_size = 1000; for( $i=0,$c=count($players); $i<$c; $i+=$batch_size ) { $db->beginTransaction(); try { for( $k=$i; $k<$c && $k<$i+$batch_size; $k++ ) { $player = $players[$k]; $sql->execute([ ":name" => $player->name, ":level" => $player->level, ":vocation" => $player->vocation, ":world" => $player->world, ":time" => $player->time, ":online" => $player->online ]); } } catch( PDOException $e ) { $db->rollBack(); // at this point you would want to implement some sort of error handling // or potentially re-throw the exception to be handled at a higher layer break; } $db->commit(); }