2013-05-22 6 views
0

У меня есть скрипт для заполнения базы данных MySQL с сервера DB2. Он работает, но, кажется, он вставляет строки в MySQL с чрезвычайно низкой скоростью. Процесс сервера выполняется на ~ 1% процессора во время работы скрипта, и мне интересно, как я могу ускорить вставки.Заполнение базы данных MySQL из базы данных DB2

По соображениям безопасности администратор базы данных 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 до 21 миллиона строк.

Я там думать, что я могу связать прописные параметры в запросе, чтобы избежать strtolower функций все в foreach, но кроме этого незначительных изменений будет какие-либо предложения о том, как улучшить производительность сценария?

ответ

0

После краткого исследования, как InnoDB выполнял операции, я сделал следующее, чтобы ускорить вставки:

  • Использование transactions (т.е. выключить Autocommit): $this->mysql->beginTransaction(). Количество запросов на транзакцию было ограничено, хотя я уверен, что MySQL в любом случае зафиксировал бы, когда буфер InnoDB заполнил
  • Disable foreign key checks: SET foreign_key_checks = 0. База данных DB2 имела довольно высокую целостность, поэтому это была безопасная операция.
  • Отключить уникальные проверки ключей: SET unique_checks = 0. База данных DB2 уже применяла уникальные ключи, поэтому это было безопасно.
  • Enable uncommitted reads: SET 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 Data Server, чтобы иметь возможность запускать процессор командной строки DB2 для EXPORT.

+0

+1 Согласовано дамп + насыпной импорт должен быть лучшим способом –

+0

В настоящее время это не вариант для нас, как мы имеют очень мало контроля над сервером, однако я буду помнить это предположение, когда мы переходим на новый сервер. Благодаря! –

0

Попробуйте экспортировать все данные в формат CSV-файла, а затем используйте загрузочную информацию для загрузки в свою базу данных MySQL. Утилиты загрузки и экспорта обязательно выполняются быстрее, чем выборка одной строки и вставка ее один за другим.