原因:我被分配运行一些脚本来推进网站,这是一个梦幻足球网站,该网站的多个实例位于不同的域中。有些拥有超过 8 万用户,每个用户应该拥有一个由 15 名玩家组成的团队。因此,某些表具有 No.users x No.players 行。
但是,有时脚本会失败并且结果会损坏,因此在执行脚本之前我必须备份 10 个有问题的表。尽管如此,我仍然需要备份表以保留用户操作的历史记录。因为足球比赛可能会持续 50 多个比赛周。
任务:使用 PHP 脚本复制数据库表。当我开始时,我曾经使用 sqlyog 备份表。它可以工作,但是很耗时,因为我必须等待每个表都被复制。此外,对于大型表,sqlyog应用程序在复制大型表期间会崩溃,这可能非常烦人。
当前解决方案:我创建了一个简单的应用程序,其界面可以完成这项工作并且效果很好。它由三个文件组成,第一个用于数据库连接,第二个用于数据库操作,第三个用于用户界面并使用第二个文件的代码。 问题是,有时它会卡在复制表过程的中间。
目标:创建一个供管理员使用的应用程序,以方便使用mysql+php进行数据库备份。
我的问题:如何确保复制脚本一定会完全备份表而不会挂起服务器或中断脚本。
在这里,我将包含我的复制函数代码,但基本上这是我认为问题所在的两行关键行:
//duplicate tables structure
$query = "CREATE TABLE $this->dbName.`$newTableName` LIKE $this->dbName.`$oldTable`";
//duplicate tables data
$query = "INSERT INTO $this->dbName.`$newTableName` SELECT * FROM $this->dbName.`$oldTable`";
其余代码仅用于验证以防发生错误。如果您想查看整个代码,请成为我的客人。函数如下:
private function duplicateTable($oldTable, $newTableName) {
if ($this->isExistingTable($oldTable))
{
$this->printLogger("Original Table is valid -table exists- : $oldTable ");
}
else
{
$this->printrR("Original Table is invalid -table does not exist- : $oldTable ");
return false;
}
if (!$this->isExistingTable($newTableName))// make sure new table does not exist alrady
{
$this->printLogger("Distination Table name is valid -no table with this name- : $newTableName");
$query = "CREATE TABLE $this->dbName.`$newTableName` LIKE $this->dbName.`$oldTable`";
$result = mysql_query($query) or $this->printrR("Error in query. Query:\n $query\n Error: " . mysql_error());
}
else
{
$this->printrR("Distination Table is invalid. -table already exists- $newTableName");
$this->printr("Now checking if tables actually match,: $oldTable => $newTableName \n");
$varifyStatus = $this->varifyDuplicatedTables($oldTable, $newTableName);
if ($varifyStatus >= 0)
{
$this->printrG("Tables match, it seems they were duplicated before $oldTable => $newTableName");
}
else
{
$this->printrR("The duplicate table exists, yet, doesn't match the original! $oldTable => $newTableName");
}
return false;
}
if ($result)
{
$this->printLogger("Query executed 1/2");
}
else
{
$this->printrR("Something went wrong duplicateTable\nQuery: $query\n\n\nMySql_Error: " . mysql_error());
return false;
}
if (!$this->isExistingTable($newTableName))//validate table has been created
{
$this->printrR("Attemp to duplicate table structure failed $newTableName table was not found after creating!");
return false;
}
else
{
$this->printLogger("Table created successfully: $newTableName");
//Now checking table structure
$this->printLogger("Now comparing indexes ... ");
$autoInc = $this->checkAutoInc($oldTable, $newTableName);
if ($autoInc == 1)
{
$this->printLogger("Auto inc seems ok");
}
elseif ($autoInc == 0)
{
$this->printLogger("No inc key for both tables. Continue anyways");
}
elseif ($autoInc == -1)
{
$this->printLogger("No match inc key!");
}
$time = $oldTable == 'team_details' ? 5 : 2;
$msg = $oldTable == 'team_details' ? "This may take a while for team_details. Please wait." : "Please wait.";
$this->printLogger("Sleep for $time ...\n");
sleep($time);
$this->printLogger("Preparing for copying data ...\n");
$query = "INSERT INTO $this->dbName.`$newTableName` SELECT * FROM $this->dbName.`$oldTable`";
$this->printLogger("Processing copyign data query.$msg...\n\n\n");
$result = mysql_query($query) or $this->printrR("Error in query. Query:\n $query\n Error: " . mysql_error());
// ERROR usually happens here if large tables
sleep($time); //to make db process current requeste.
$this->printLogger("Query executed 2/2");
sleep($time); //to make db process current requeste.
if ($result)
{
$this->printLogger("Table created ($newTableName) and data has been copied!");
$this->printLogger("Confirming number of rows ... ");
/////////////////////////////////
// start checking count
$numRows = $this->checkCountRows($oldTable, $newTableName);
if ($numRows)
{
$this->printLogger("Table duplicated successfully ");
return true;
}
else
{
$this->printLogger("Table duplicated, but, please check num rows $newTableName");
return -3;
}
// end of checking count
/////////////////////////////////
}//end of if(!$result) query 2/2
else
{
$this->printrR("Something went wrong duplicate Table\nINSERT INTO $oldTable -> $newTableName\n\n$query\n mysql_error() \n " . mysql_error());
return false;
}
}
}
正如您所注意到的,该函数仅复制一个表,这就是为什么还有另一个函数从用户那里获取一组表,并将表名称数组逐一传递给duplicateTable()。 这个问题应该包含任何其他函数,请告诉我。
我想到了一个解决方案,逐部分复制表格会增加任何改进吗?我不确定“插入”是如何工作的,但也许如果我可以一次插入25%,它可能会有所帮助?
最佳答案
However Sometimes the script fails and the result gets corrupted, therefore I must backup 10 tables in question before i execute the script.
可能您需要在这里使用另一个解决方案:transactions 。您需要将失败脚本中使用的所有查询包装到事务中。如果事务失败,所有数据将与操作开始时相同。如果查询正确执行 - 就OK了。
关于php - 有效地复制/复制/备份数据库表 - mysql,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14038348/