0

現在、DB2 サーバーから MySQL データベースにデータを入力するためのスクリプトがあります。動作しますが、非常に遅い速度で行を MySQL に挿入しているようです。スクリプトの実行中、サーバー プロセスは約 1% の CPU で実行されています。挿入を高速化するにはどうすればよいか考えています。

セキュリティ上の理由から、DB2 データベースの管理者は、データベース内の必要なテーブルの読み取り専用ビューのみを提供してくれました。

これは私のスクリプトです:

<?php

$selectQuery = "SELECT 
                    PK AS COL1,
                    COL2,
                    COL3,
                    COL4,
                    CASE WHEN DATE > '" . date('Y-m-d') . "'
                      THEN 1
                      ELSE 0
                      END AS COL5
                FROM table1";

$insertQuery = "INSERT INTO `table1` (
                    `fk`,
                    `col2`,
                    `col3`,
                    `col4`,
                    `col5`,
                    `last_updated`
                )
                SELECT :col1, f.`fid`, :col3, :col4, :col5, NOW()
                    FROM f
                    WHERE f.`code` = :col2
                    LIMIT 1
                ON DUPLICATE KEY UPDATE
                    `col2` = VALUES(col2),
                    `col3` = VALUES(col3),
                    `col4` = VALUES(col4),
                    `col5` = VALUES(col5),
                    `last_updated` = NOW();";

$paramTypes = array(
    'col1' => PDO::PARAM_STR,
    'col2' => PDO::PARAM_STR,
    'col3' => PDO::PARAM_STR,
    'col4' => PDO::PARAM_STR,
    'col5' => PDO::PARAM_BOOL
);

$sync->populate($selectQuery, $insertQuery, $paramTypes);

同期クラス (の$syncインスタンスであるクラス):

<?php

class SyncObject {
    private $db2;
    private $db2_user = '...';
    private $db2_pass = '...';
    private $db2_dbname = '...';
    private $db2_host = 'secure.example.net';
    private $db2_port = ...;

    private $mysql;

    public function __construct() {
        // Establish a DB2 connection
        $this->db2 = db2_pconnect("DATABASE={$this->db2_dbname};HOSTNAME={$this->db2_host};PORT={$this->db2_port};PROTOCOL=TCPIP;UID={$this->db2_user};PWD={$this->db2_pass};", '', '');

        // Establish a MySQL connection
        $this->mysql = new PDO('mysql:host=secure-mysql.example.net;port=...;dbname=...', '...', '...', array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
}

    public function populate($selectQuery, $insertQuery, $paramTypes = array()) {

        $insStmt = $this->mysql->prepare($insertQuery);

        foreach ($paramTypes as $parameterName => $parameterType) {

            $$parameterName = '';

            $insStmt->bindParam(":$parameterName", $$parameterName, $parameterType);
        }

        // Retrieve the data

        $stmt = db2_exec($this->db2, $selectQuery);

        while ($row = db2_fetch_assoc($stmt)) {
            foreach ($row as $fieldName => &$fieldValue) {

                $fieldName = strtolower($fieldName);

                $$fieldName = trim($fieldValue);

                $insStmt->execute();
            }
        }
    }
}

ちなみに、このpopulateメソッドはテーブルごとに 1 回、合計 6 回呼び出されます。ここでは 1 つのテーブルのみを示しました。テーブルのサイズは、20 行から 2100 万行の範囲です。

クエリで大文字のパラメーターをバインドして、strtolower関数をすべてforeach.

4

3 に答える 3

0

InnoDB が操作を実行する方法を簡単に調査した後、挿入を高速化するために次のことを行いました。

  • トランザクションを使用します(つまり、自動コミットをオフにします): $this->mysql->beginTransaction(). トランザクションごとのクエリの量は制限されていましたが、InnoDB バッファーがいっぱいになったときに MySQL がとにかくコミットすることは確かです
  • 外部キー チェックを無効にします: SET foreign_key_checks = 0. DB2 データベースは完全性が非常に高いため、これは安全な操作でした。
  • 一意のキー チェックを無効にします: SET unique_checks = 0. DB2 データベースはすでに固有のキーを適用していたので、これは安全でした。
  • コミットされていない読み取りを有効にします: SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED.

さらに考慮すべきことはInnoDB システム変数でしたが、これらはサーバーへのアクセスが制限されているため実際には変更できません。

このページも役立つかもしれませんが、ここにリストされているほとんどのものをリストしています: http://dev.mysql.com/doc/refman/5.6/en/optimizing-innodb-bulk-data-loading.html

于 2013-05-23T16:57:33.617 に答える