你做错了几件事。您必须考虑的第一件事是您使用的是什么 MySQL 引擎。
默认引擎是 InnoDB,之前默认引擎是 MyISAM。
我将在假设您使用 InnoDB 的情况下编写此答案,出于多种原因您应该使用它。InnoDB 以一种称为自动提交模式的方式运行。这意味着您所做的每个查询都包含在事务中。为了把它翻译成我们普通人可以理解的语言——你在没有指定BEGIN WORK;
块的情况下执行的每个查询都是一个事务——因此,MySQL 将等到硬盘驱动器确认数据已写入。
知道硬盘驱动器很慢(机械驱动器仍然是最广泛使用的驱动器),这意味着您的插入将与硬盘驱动器一样快。通常,机械硬盘每秒可以执行大约 300 次输入输出操作,因此假设您每秒可以执行 300 次插入 - 是的,您将等待相当长的时间才能插入 100 万条记录。
所以,知道事情是如何运作的——你可以利用它们来发挥你的优势。
HDD 每个事务写入的数据量通常非常小(4KB 甚至更少),并且知道今天的 HDD 可以写入超过 100MB/秒 - 这表明我们应该将多个查询包装到单个事务中。
这样,MySQL 将发送相当多的数据并等待 HDD 确认它写入了所有内容,并且整个世界都很好而且花花公子。
因此,假设您要填充 1M 行 - 您将执行 1M 查询。如果您的事务一次提交 1000 个查询,您应该只执行大约 1000 个写入操作。
这样,您的代码就变成了这样:
(我不熟悉 mysqli 接口,所以函数名称可能是错误的,并且看到我在没有实际运行代码的情况下输入 - 该示例可能无法正常工作,因此使用它需要您自担风险)
function generateRandomData()
{
$db = new mysqli('localhost','XXX','XXX','scores');
if(mysqli_connect_errno()) {
echo 'Failed to connect to database. Please try again later.';
exit;
}
$query = "insert into scoretable values(?,?,?)";
// We prepare ONCE, that's the point of prepared statements
$stmt = $db->prepare($query);
$start = 0;
$top = 1000000;
for($a = $start; $a < $top; $a++)
{
// If this is the very first iteration, start the transaction
if($a == 0)
{
$db->begin_transaction();
}
$id = rand(1,75000);
$score = rand(1,100000);
$time = rand(1367038800 ,1369630800);
$stmt->bind_param("iii",$id,$score,$time);
$stmt->execute();
// Commit on every thousandth query
if( ($a % 1000) == 0 && $a != ($top - 1) )
{
$db->commit();
$db->begin_transaction();
}
// If this is the very last query, then we just need to commit and end
if($a == ($top - 1) )
{
$db->commit();
}
}
}