2014-11-05 147 views
0

我正在使用下面的腳本將大型csv文件導入到我的數據庫。增強csv文件數據庫導入

如果該表爲空,則在本地計算機上完成該過程需要大約5分鐘的時間。

如果我使用該文件更新同一張表上的現有值,則需要15分鐘以上才能完成。

我的csv文件包含大約35,000行。

我該如何加快流程?

if ($request->get($_POST["action"]) == "import") { 

     $file = $upload->file_upload("import", "media/import"); 
     if (file_exists(DIR_UPLOAD_PHOTO . "/media/import/" . $file)) { 

      $file = DIR_UPLOAD_PHOTO . "/media/import/" . $file; 
      $handle = fopen($file, "r"); 

      if ($handle) { 
       $lines = explode("\r", fread($handle, filesize($file))); 
      } 

      $total_array = count($array); 

      $x = 0; 

      foreach ($lines as $line) { 

       if ($x >= 1) { 
        $data = explode("|", $line); 

        $titlu   = trim(addslashes($data[0])); 
        $alias   = $this->generate_seo_link($titlu); 
        $gramaj   = trim($data[1]); 
        $greutate  = trim($data[2]); 
        $pret_total  = trim($data[3]); 
        $pret_redus  = trim($data[4]); 
        $poza   = trim($data[5]); 
        $pret_unitar = trim($data[6]); 
        $categorie  = trim($data[7]); 
        $brand   = trim(addslashes($data[8])); 
        $descriere  = trim(addslashes($data[9])); 
        $vizibil  = trim($data[10]); 
        $cod   = trim($data[11]); 
        $nou   = trim($data[12]); 
        $cant_variabila = trim($data[13]); 
        $congelat  = trim($data[14]); 
        $tva   = trim($data[15]); 
        $stoc   = trim($data[16]); 

        if ($cod != "" && $cod != " ") { 

         $verificare = $database->select("SELECT alias FROM produse WHERE alias LIKE '%" . $alias . "%'"); 
         for ($i = 0; $i < $database->countRows(); $i++) { 
          if ($alias == $verificare['alias'][$i]) { 
           $alias = $this->increment_string($alias, '_', 1); 
          } else { 
           $alias = $alias; 
          } 
         } 

         $database->insert(sprintf("insert into produse set 
          titlu='%s', 
          alias='%s', 
          gramaj='%s', 
          greutate='%s', 
          prettotal='%s', 
          pretredus='%s', 
          poza='%s', 
          pretunitar='%s', 
          categorie='%d', 
          brand='%s', 
          descriere='%s', 
          vizibil='%d', 
          cod='%s', 
          nou='%d', 
          cant_variabila='%d', 
          congelat = '%d', 
          tva = '%s', 
          stoc = '%d' 

          on duplicate key update 

          titlu='%s', 
          gramaj='%s', 
          greutate='%s', 
          prettotal='%s', 
          pretredus='%s', 
          poza='%s', 
          pretunitar='%s', 
          categorie='%d', 
          brand='%s', 
          descriere='%s', 
          vizibil='%d', 
          cod='%s', 
          nou='%d', 
          cant_variabila='%d', 
          congelat = '%d', 
          tva='%s', 
          stoc= '%d'", 

          $titlu, $alias, 
          $gramaj, $greutate, $pret_total, $pret_redus, $poza, $pret_unitar, $categorie, 
          $brand, $descriere, $vizibil, $cod, $nou, $cant_variabila, $congelat, 
          $tva, $stoc, 

          $titlu, $gramaj, $greutate, 
          $pret_total, $pret_redus, $poza, $pret_unitar, $categorie, $brand, $descriere, 
          $vizibil, $cod, $nou, $cant_variabila, $congelat, $tva, $stoc)); 

    } 
    } 
    $x++; 
    } 

    } 
    } 

這裏是我的遞增函數

function increment_string($str, $separator = '-', $first = 1){ 
    preg_match('/(.+)'.$separator.'([0-9]+)$/', $str, $match); 

    return isset($match[2]) ? $match[1].$separator.($match[2] + 1) : $str.$separator.$first; 

    } 
+1

可能比codeoverview更多比stackoverflow – Duniyadnd 2014-11-05 14:35:11

+0

這可能是由於索引必須檢查和每個插入更新。您可以使用[EXPLAIN](http://dev.mysql.com/doc/refman/5.6/en/explain.html)查看在插入過程中正在使用的索引(如果有的話)。 – 2014-11-05 14:37:28

+1

@JayBlanchard - 爲什麼會在插入時使用** **索引?爲什麼人們立即認爲每個數據庫放緩都可以通過索引解決。這裏的問題是可用的I/O操作有限。機械驅動器每秒可以擠壓300個I/O。這意味着每秒300個查詢。如果這些查詢是組合MULTIPLE查詢的交易,那麼可以有效使用HDD帶寬。基本上,強制磁盤在單個I/O中刷新500個查詢可以加快速度。這與索引無關**。 – 2014-11-05 14:47:37

回答

0

推到選擇的INSERT,使他們在服務器上都運行,而不是去從客戶端回和第四個服務器。

1

首先,你做的越少 - 速度越快。但是,由於硬盤驅動器,很多數據庫導入都很慢。不是因爲CPU,也不是因爲RAM不足 - 而是硬盤驅動器。

原因如下:硬盤按照的輸入輸出操作每秒運行 - 我將它稱爲I/O。這是製造商不做廣告的數字。他們做廣告,比如bandwith和突發讀物,這些大多是無用的數字 - 像鼠標的DPI。

機械磁盤的可用I/O數量相對較少。該數字取決於驅動器,它可以是100到400個I/O之間的任何值。 固態硬盤有更多的I/O數量,從5000到80k(甚至更多)。

這意味着機械磁盤可以在1秒內執行400次寫入,而SSD可以執行5000次。 問題是數據庫查詢通常數據量很小(約4KB)。

如果你做簡單的數學 - 400 I/O * 4KB - 你得到的數字約1.6 MB /秒。它表明你正在花費所有的I/O,但是要佔用磁盤帶寬的所有容量。

這也暗示你可以發出更大的數據寫入每個I/O。 在真人語言中,它僅僅意味着你應該開始一個事務,發出幾個INSERT查詢(比如50個INSERT),然後提交事務。

這樣你就花費了50個插入的1個I/O。反過來,它快50倍。如果您要使用準備好的語句,這將變得更加高效,因爲MySQL在每次發送時都不必查詢查詢。

我不會發送任何代碼,因爲您應該可以自行修復它。此外,您的代碼已針對SQL注入打開。你需要修改幾件事情,如果你不確定準備好的陳述是什麼,那麼就喊回來。

+0

我正在使用安裝了wamp的主windows分區的SSD。關於sql注入我應該怎麼做? – speedy 2014-11-05 15:45:50

+1

你說你已經在使用PDO了。你只需要使用準備好的語句,那裏有相當多的資源。實際上寫起來比查詢已經很簡單,而且在處理字符串清理時,它會爲您處理所有問題。另外,我會重新思考在掃描整個數據集的每個插入內容時,增加別名或其它任何內容的策略。這絕對有助於減緩插入過程。 – 2014-11-05 15:58:49

+0

更新我的問題,用別名LIKE'%「替代alias FROM別名' – speedy 2014-11-05 16:28:25