2

理由:私は Web サイトを進めるスクリプトを実行するように割り当てられました。これはファンタジー フットボール サイトであり、サイトのいくつかのインスタンスが異なるドメインに配置されています。一部のユーザーは 8 万人を超え、各ユーザーは 15 人のプレーヤーで構成されるチームを持つことになっています。したがって、一部のテーブルには No.users x No.players 行があります。

ただし、スクリプトが失敗して結果が破損する場合があるため、スクリプトを実行する前に、問題の 10 個のテーブルをバックアップする必要があります。それにもかかわらず、ユーザー アクションの履歴記録を保持するために、テーブルをバックアップする必要があります。サッカーの試合は 50 週間以上続く場合があるためです。

タスク: php スクリプトを使用して db テーブルを複製します。私が始めたとき、私はsqlyogを使用してテーブルをバックアップしていました。動作しますが、各テーブルが複製されるのを待たなければならないので時間がかかります。さらに、大きなテーブルの場合、大きなテーブルの複製中にsqlyogアプリケーションがクラッシュし、非常に煩わしい場合があります。

現在の解決策:仕事をするインターフェイスを備えた単純なアプリケーションを作成しましたが、うまく機能します。これは 3 つのファイルで構成されています。1 つはデータベース接続用、2 番目はデータベース操作用、3 番目はユーザー インターフェイス用、および 2 番目のファイルのコードを使用するためのものです。 問題は、テーブルの複製プロセスの途中でスタックすることがあります。

目的: mysql+php を使用してデータベースのバックアップを容易にするために管理者が使用するアプリケーションを作成すること。

私の質問:サーバーをハングさせたり、スクリプトを中断したりせずに、複製スクリプトが確実にテーブルを完全にバックアップするようにする方法。

ここに、関数を複製するためのコードを含めますが、基本的にこれらは、問題があると思われる2つの重要な行です。

//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;
            }
        }
    }

関数が 1 つのテーブルを複製するだけであることに気付いたように、ユーザーからテーブルの配列を取得し、テーブル名の配列を 1 つずつ duplicateTable() に渡す別の関数があるのはそのためです。この質問には他の機能を含める必要があります。お知らせください。

1つの解決策が頭に浮かびます。テーブルを部分ごとに複製すると改善が追加されます.Insert intoがどのように機能するかはわかりませんが、一度に25%を挿入できれば役立つでしょうか?

4

2 に答える 2

2

ただし、スクリプトが失敗して結果が破損する場合があるため、スクリプトを実行する前に、問題の 10 個のテーブルをバックアップする必要があります。

おそらく、ここで別のソリューションを使用する必要があります: transactions。失敗したスクリプトで使用しているすべてのクエリをトランザクションにラップする必要があります。トランザクションが失敗した場合、すべてのデータは操作の開始時と同じになります。クエリが正しく実行された場合 - OK です。

于 2012-12-26T09:40:21.783 に答える
1

なぜ毎回テーブルを複製するのですか.. クラスターは、テーブルの複製コピーを分散方式で作成できる優れたオプションであり、はるかに信頼性が高く安全です。

于 2012-12-26T09:22:48.483 に答える