因此,我尝试建立一个小型数据库来跟踪我们联盟中弹球机上的高分。我有一个用户表,其中只有一个AI ID列和一个电子邮件地址列。然后我有一个游戏表,其中有一个AI ID列和弹球机的名称。由于这是一个多对多的关系,我创建了第三个表scores,其中有user_id、game_id、和得分作为列。
编辑:包括读取代码:
$file = fopen('scores.txt', 'r') or die("Unable to open file.");
// Loop through the file line by line
$line_number = 1;
while (($line = fgets($file)) !== false) {
// Reset flags
$email_exists = 0;
$game_exists = 0;
if (isset($email_id)) unset($email_id);
if (isset($game_id)) unset($game_id);
echo ($line_number . " ");
// Split the line into components
$line = rtrim($line);
$array = explode(",", $line, 3);
$email = strtolower($array[0]);
$game = $array[1];
$score = $array[2];
$stmt = $db->prepare ("SELECT email_id FROM users WHERE email_address = ?");
$stmt->execute(array($email))
if ($stmt->rowCount() < 1) {
$stmt = $db->prepare("INSERT INTO users (email_address) VALUES (?)");
$stmt->execute(array($email))
$email_id = $db->lastInsertId();
} else {
$row = $stmt->fetch();
$email_id = $row['email_id'];
$email_exists = 1;
}
我使用类似的代码来检查我是否已经有一个游戏列在数据库中。我需要得到游戏的ID号和第三部分的电子邮件地址,这是看用户是否已经有了那个游戏的分数,如果他们已经有了新的分数更高。
if ($email_exists == 0 || $game_exists == 0) {
// New user or game added to DB - no prior score can exist
$stmt = $db->prepare("INSERT INTO scores VALUES (?,?,?)");
$stmt->execute(array($email_id,$game_id,$score));
} else {
$stmt = $db->prepare("SELECT * FROM scores WHERE email_id = ? AND game_id = ?");
$stmt->execute(array($email_id,$game_id));
if ($stmt->rowCount() == 0) {
// No previous score for this game
$stmt = $db->prepare("INSERT INTO scores VALUES (?,?,?)");
$stmt->execute(array($email_id,$game_id,$score));
} else {
// Previous score exists
$row = $stmt->fetch();
if ($score > $row['score']) {
// New score is higher
$stmt = $db->prepare("UPDATE scores SET score = ? " .
. "WHERE email_id = ? AND game_id =?");
$stmt->execute(array($score, $email_id, $game_id));
// No action needed if new score is lower
}
}
}
代码看起来工作得很好,但是很慢。另外,在几千条记录之后,它似乎会使脚本超时或什么的。有没有更好的方法来使这个工作?
我试着用Python重新编码它,但是它更慢,而且看起来它甚至没有在数据库中插入行。我几乎不懂Python,这可能没有帮助。
我想创建一个数组并存储需要插入的项,然后一次插入100行或类似的内容,但我需要获取scores连接表的id。我还考虑在数据库中使用UNIQUE约束,并试图找出如何重写插入代码,以使用该约束来防止重复的电子邮件地址或游戏。
2条答案
按热度按时间idv4meu81#
创建一个包含参数email,game_id和score的存储过程。让这个过程为你做所有的SQL工作。你的PHP代码将被缩减为一个调用这个过程的循环。结果应该更快,更容易维护:
如果这个循环仍然太慢,那么是其他东西导致了它的减速。
41zrol4v2#
这里有很多改进的空间。当涉及到数据库速度时,您的主要目标通常应该是减少对数据库服务器的访问次数。
首先,你要对每一个CSV行执行email-to-id查询,这是没有必要的。最多,你应该对每个用户执行一次并缓存它。更好的是,你可以对整个集合执行一次,将整个集合读入内存数组。类似于:
这将为您提供如下数组:
在脚本开始时执行一次,并在此期间将其保存在内存中。通过此操作,您可以立即查找给定电子邮件的ID。这将删除7999次对数据库的访问。您实际上是在用内存换取CPU和磁盘时间。如果您遇到一封尚未包含在数组中的电子邮件,您可以将其插入并添加到数组中。
接下来,将准备操作移出循环迭代,这将删除至少3 * 7999个数据库匹配项,最多可能删除5 * 7999个匹配项。
接下来,使用fgetcsv()而不是explode(),因为它更简单,并且可以正确处理引用。在执行单个插入之前处理整个CSV。如果你打算丢弃大部分记录,那么创建如此巨大的数据库流量是愚蠢的。因此,首先计算最高值,然后只使用以下内容访问数据库:
给定输入文件:
这将为每个用户生成一个最高分数数组:
然后,您可以迭代该数组,并且只基于这些记录执行插入/更新。这将为每个冗余CSV行保存两个查询。