2014-03-28 79 views
2

我在寫數據庫導入功能。我的語言是PHP。我的數據是JSON格式。mysql |數據庫表導入策略

我下面的代碼:

public function import($data = '') { 

    if (!isset($data)) { 
     return array(
      'error' => "Error: no data" 
     ); 
    } 

    $data_arr = json_decode($data, true); 

    if (is_array($data_arr) && sizeof($data_arr)) { 

     // Truncate DB table 

     $sql = 'TRUNCATE `ms_data`'; 
     $this->db->query($sql)->execute(); 

     // Import data 
     $sql = 'INSERT INTO `ms_data` (
       `id`, 
       `name`, 
       `parent`, 
       `ordering` 
       ) VALUES (
        :id, 
        :name, 
        :parent, 
        :ordering 
       )'; 

     foreach($data_arr as $d) { 

      $this->db->query($sql) 
       ->bind(":id",  $d['id']) 
       ->bind(":name",  trim($d['name'])) 
       ->bind(":ordering", $d['ordering']) 
       ->execute(); 
     } 

     return array(
      'status' => 1, 
      'message' => 'Data has been imported' 
     );     

    } else { 

     return array(
      'error' => "Input is not array" 
     ); 
    }  
} 

這是工作的代碼,但:也許你知道任何代碼上面的問題,我不知道現在或任何改進的建議?

謝謝!

+0

讓我們希望你永遠不必處理大量的數據 –

+0

這個函數將用於我們的商店腳本(產品導入):) – user889349

+0

我有一些問題後第一次審查:你可以發佈'顯示創建TABLE ms_data'的表結構的詳細信息,請?你用mysql驅動程序或mysqli類使用PDO嗎?父參數發生了什麼?它永遠不會結合。大概發佈$ this-> db實例的類也是有用的。 – citizen404

回答

2

有一個問題,我看到:

如果您加載了很多使用此功能的信息,你需要相當長的一段時間才能結束。

您可以使用單個查詢加載所有的數據,用這樣的代碼:

<?php 
public function import($data = '') { 

    if (!isset($data)) { 
     return array(
     'error' => "Error: no data" 
    );  
    } 

    $data_arr = json_decode($data, true); 

    if (is_array($data_arr) && sizeof($data_arr)) { 

     // Truncate DB table 

     $sql = 'TRUNCATE `ms_data`'; 
     $this->db->query($sql)->execute(); 

     $itemCount = count($data_arr); 

     // Import data 
     $sql  = 'INSERT INTO `ms_data` (
        `id`, 
        `name`, 
        `parent`, 
        `ordering` 
        ) VALUES '; 

     for($i=1; $i <= $itemCount; $i++) 
     { 
      // Last item should not put comma after values. 
      if ($i == $itemCount) 
      { 
       $sql = $sql . "(?,?,?,?)" 
      } 
      else 
      { 
       $sql = $sql . "(?,?,?,?)," 
      } 
     } 

     $stmt = $this->db->prepare($sql); 

     $i = 1; 
     foreach($data_arr as $d) { 


      $stmt->bindParam($i++, $d['id']) 
      ->bindParam($i++, trim($d['name'])) 
      ->bindParam($i++, $d['ordering']); 
     } 

     $stmt->execute(); 

     return array(
      'status' => 1, 
      'message' => 'Data has been imported' 
     );     

    } else { 

     return array(
      'error' => "Input is not array" 
     ); 
    } 
}  
?> 

使用這種方式,你會插入一個查詢所有的行,這樣可以減少執行時間很多,並將是一個atomic operation

+1

請注意,這也會在非常大的數據集上失敗。這是數千或數百萬,取決於MySQL的MAX_ALLOWED_PACKET,以及您設置的參數的大小。順便說一下,上面的代碼中有一些代碼重複。更改爲:'$ sql = $ sql。 「(,,,????)」; if($ i <$ itemCount){$ sql。=','; }' – Gerben

0

如果你有大量的數據,你應該做到以下幾點:

1)創建將用於加載數據的新表:CREATE TABLE new_data LIKE ms_data
2)填充數據,你認爲合適:即INSERT INTO new_data VALUES (?,?,?,?)
3)用新表替換舊錶:RENAME ms_data TO old_ms_data, new_data TO ms_data。這個操作是原子的,所以對其他用戶應該是不可見的。
4)清理,刪除舊錶:DROP TABLE old_ms_data

CREATE TABLEDROP TABLERENAME TABLE所有會由於RENAME TABLE置換中的數據的性質隱含的承諾,所以你不能做到這一點作爲一個單一的交易,但' ms_data'這仍然是原子。

請注意,如果您爲臨時表使用靜態名稱(例如'new_data'),則不能同時執行兩個加載進程。