2017-10-28 121 views
0

我試圖建立一個腳本,我需要讀取txt文件並使用文件上的行執行某個過程。例如,我需要檢查ID是否存在,如果信息已更新(如果有),則更新當前表(如果不存在),則在另一個臨時表上插入一個新行,稍後手動檢查。PHP提高執行多個查詢時讀取一千行文件的性能

這些文件可能包含超過20,30000行。

當我剛剛讀取文件並從行中打印一些dummie內容時,需要40-50ms。但是,當我需要連接到數據庫來執行所有這些驗證時,由於超時而在停止之前停止。

這是我在做什麼至今:

$handle = fopen($path, "r") or die("Couldn't get handle"); 
if ($handle) { 
    while (!feof($handle)) { 
     $buffer = fgets($handle, 4096); 
     $segment = explode('|', $buffer); 

     if (strlen($segment[0]) > 6) { 
      $param = [':code' => intval($segment[0])]; 
      $codeObj = Sql::exec("SELECT value FROM product WHERE code = :code", $param); 

      if (!$codeObj) { 
       $param = [ 
        ':code' => $segment[0], 
        ':name' => $segment[1], 
        ':value' => $segment[2], 
       ]; 
       Sql::exec("INSERT INTO product_tmp (code, name, value) VALUES (:code, :name, :value)", $param); 
      } else { 
       if ($codeObj->value !== $segment[2]) { 
        $param = [ 
         ':code' => $segment[0], 
         ':value' => $segment[2], 
        ]; 
        Sql::exec("UPDATE product SET value = :value WHERE code = :code", $param); 
       } 
      } 
     } 
    } 

    fclose($handle); 
} 

這是我的SQL類與PDO連接並執行查詢:

public static function exec($sql, $param = null) { 
    try { 
     $conn = new PDO('mysql:charset=utf8mb4;host= '....'); // I've just deleted the information to connect to the database (password, user, etc.) 
     $q = $conn->prepare($sql); 

     if (isset($param)) { 
      foreach ($param as $key => $value) { 
       $$key = $value; 
       $q->bindParam($key, $$key); 
      } 
     } 

     $q->execute(); 
     $response = $q->fetchAll(); 

     if (count($response)) return $response; 
     return false; 
    } catch(PDOException $e) { 
     return 'ERROR: ' . $e->getMessage(); 
    } 
} 

正如你所看到的,每個查詢我通過Sql::exec()來做,正在打開一個新的連接。我不知道這是否可能是此過程出現延遲的原因,因爲當我沒有執行任何Sql查詢時,腳本在ms內運行。

或者其他部分的代碼可能會導致這個問題?

+0

例如,您是通過命令行還是通過HTTP和Apache在後臺運行它。似乎更適合後臺進程。 – ArtisticPhoenix

+0

當然,我不會連接到循環中的數據庫,你應該保存連接到一個類屬性或你有什麼,並重新使用它。 – ArtisticPhoenix

+0

@ArtisticPhoenix這是通過cron作業在後臺運行。我的意思是,cronjob調用這個php文件來執行這個函數,但它也可以手動調用(如果需要的話 - 不常見),或者在這個測試階段,我仍然在構建腳本,然後我正在通過xhr request – celsomtrindade

回答

0

首先,讓你的功能像這樣, 避免多重連接,並且也擺脫無用的代碼。

public static function getPDO() { 
    if (!static::$conn) { 
     static::$conn = new PDO('mysql:charset=utf8mb4;host= ....'); 
    } 
    return static::$conn; 
} 
public static function exec($sql, $param = null) { 
    $q = static::getPDO()->prepare($sql); 
    $q->execute($param); 
    return $q; 
} 

然後創建唯一索引爲code

然後使用一個單一的INSERT ... ON DUPLICATE KEY UPDATE查詢,而不是你thrree查詢

您可能還需要來包裝你在插入一筆交易,它可以加速插入達70次。

+0

「無用的代碼」是什麼意思我看到你刪除了與'bindParam'相關的那些行。但是當我像這樣運行查詢時,我不需要使用它們'插入表(名稱)VALUE(:name);'? 「插入交易」的含義也不清楚,你能解釋一下嗎? – celsomtrindade

+0

不,你不知道。只需把你的$參數放到execute()中,如上所示。 –