2013-05-22 79 views
0

我目前有一個用於從DB2服務器填充MySQL數據庫的腳本。它可以工作,但它似乎以極低的速度將行插入到MySQL中。當腳本運行時,服務器進程在〜1%的CPU上執行,我想知道如何加速插入。從DB2數據庫填充MySQL數據庫

出於安全原因,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->填充($ 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方法被調用六次,每一次表。我只在這裏展示過一張桌子。表格的大小從20行到2100萬行不等。

我在想,我可以在查詢中綁定大寫參數,以避免strtolower函數全部在foreach中,但除了那個小改動之外,有沒有關於如何提高腳本性能的建議?

回答

0

簡要調查的InnoDB是如何進行操作後,我做了以下以加快插入:

  • 使用transactions(即關閉自動):$this->mysql->beginTransaction()。每個事務的查詢數量是有限的,雖然我很確定MySQL會在InnoDB緩衝區填滿時承諾
  • Disable foreign key checksSET foreign_key_checks = 0。 DB2數據庫具有相當高的完整性,所以這是一個安全的操作。
  • 禁用唯一密鑰檢查:SET unique_checks = 0。 DB2數據庫已經實施了唯一的密鑰,因此這是安全的。
  • Enable uncommitted readsSET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

要考慮的其他事項是InnoDB system variables,但這些無法通過有限的服務器訪問進行更改。

本頁面也可能有所幫助,但是它列出了這裏列出的東西最:http://dev.mysql.com/doc/refman/5.6/en/optimizing-innodb-bulk-data-loading.html

2

無論你做什麼,按行插入數據都不會很好。在我看來,更好的方法是使用DB2 EXPORT命令將DB2表格數據提取到CSV文件中,然後使用MySQL LOAD DATA將它們加載到目標數據庫中。我對PHP不太熟悉,但我認爲它應該允許你使用exec()來運行外部命令。

您至少需要安裝DB2數據服務器運行時客戶端才能夠爲EXPORT運行DB2命令行處理器。

+0

+1同意轉儲+批量導入一定是更好的方式 –

+0

目前,這是不是一種選擇,對於我們,因爲我們對服務器幾乎沒有控制權,但是當我們遷移到較新的服務器時,我會牢記這一建議。謝謝! –

0

嘗試將整個數據導出爲csv文件格式,然後使用加載數據實用程序將其加載到MySQL數據庫中。加載和導出實用程序的執行速度肯定比讀取單個行並逐一插入它要快。