2

原因:我被指派运行一些脚本来推进一个网站,这是一个梦幻足球网站,并且该网站的多个瞬间位于不同的域中。有些拥有超过 80,000 个用户,每个用户应该拥有一个由 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()。此问题应包括任何其他功能,请告诉我。

一个解决方案突然出现在我的脑海中,逐部分复制表格是否会增加任何改进,我不确定 Insert into 是如何工作的,但也许如果我可以一次插入 25% 可能会有所帮助?

4

2 回答 2

2

但是有时脚本会失败并且结果会损坏,因此我必须在执行脚本之前备份 10 个有问题的表。

可能您需要在这里使用另一种解决方案:transactions。您需要将在失败脚本中使用的所有查询包装到事务中。如果事务失败,所有数据将与操作开始时相同。如果查询被正确执行 - 你没问题。

于 2012-12-26T09:40:21.783 回答
1

你为什么每次都复制表格 。CLUSTERS是一个不错的选择,它可以以分布式方式复制表格,并且更加可靠和安全。

于 2012-12-26T09:22:48.483 回答