2013-05-22 73 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数据库中。加载和导出实用程序的执行速度肯定比读取单个行并逐一插入它要快。