2017-03-01 50 views
2

我解釋說,我有一個Symfony2項目,我需要通過CSV數據庫中的csv文件導入用戶。在MySQL中導入數據之前,我必須做一些工作。我爲此創建了一個服務,一切工作都正常,但如果我將整個文件提交給服務器,則需要花費太多時間來執行和減慢服務器。我的文件通常有500到1500行,我必須將我的文件分成大約200行文件並逐個導入。如何使用PHP更有效地將csv文件導入MySQL數據庫?

我需要處理既可以在文件中也可以在數據庫中的相關用戶。相關用戶通常是孩子的父母。

這裏是我的簡化代碼:

$validator = $this->validator; 

$members = array(); 
$children = array(); 
$mails = array(); 

$handle = fopen($filePath, 'r'); 
$datas = fgetcsv($handle, 0, ";"); 

while (($datas = fgetcsv($handle, 0, ";")) !== false) { 

    $user = new User(); 

    //If there is a related user 
    if($datas[18] != ""){ 
     $user->setRelatedMemberEmail($datas[18]); 

     $relation = array_search(ucfirst(strtolower($datas[19])), UserComiti::$RELATIONSHIPS); 
     if($relation !== false) 
      $user->setParentRelationship($relation); 
    } 
    else { 
     $user->setRelatedMemberEmail($datas[0]); 
     $user->addRole ("ROLE_MEMBER"); 
    } 

    $user->setEmail($mail); 
    $user->setLastName($lastName); 
    $user->setFirstName($firstName); 
    $user->setGender($gender); 
    $user->setBirthdate($birthdate); 
    $user->setCity($city); 
    $user->setPostalCode($zipCode); 
    $user->setAddressLine1($adressLine1); 
    $user->setAddressLine2($adressLine2); 
    $user->setCountry($country); 
    $user->setNationality($nationality); 
    $user->setPhoneNumber($phone); 

    //Entity Validation 
    $listErrors = $validator->validate($user); 

    //In case of errors 
    if(count($listErrors) > 0) { 
     foreach($listErrors as $error){ 
       $nbError++; 
       $errors .= "Line " . $line . " : " . $error->getMessage() . "\n"; 
     } 
    } 

    else { 
     if($mailParent != null) 
      $children[] = $user; 

     else{ 
      $members[] = $user; 
      $nbAdded++; 
     } 
    } 

    foreach($members as $user){ 
     $this->em->persist($user); 
     $this->em->flush(); 
    } 

    foreach($children as $child){ 

     //If the related user is already in DB 
     $parent = $this->userRepo->findOneBy(array('username' => $child->getRelatedMemberEmail(), 'club' => $this->club)); 

     if ($parent !== false){ 

      //Check if someone related to related user already has the same last name and first name. If it is the case we can guess that this user is already created 
      $testName = $this->userRepo->findByParentAndName($child->getFirstName(), $child->getLastName(), $parent, $this->club); 

      if(!$testName){ 
       $child->setParent($parent); 
       $this->em->persist($child); 
       $nbAdded++; 
      } 
      else 
       $nbSkipped++; 
     } 

     //Else in case the related user is neither file nor in database we create a fake one that will be able to update his profile later. 
     else{ 

      $newParent = clone $child; 
      $newParent->setUsername($child->getRelatedMemberEmail()); 
      $newParent->setEmail($child->getRelatedMemberEmail()); 
      $newParent->setFirstName('Unknown'); 

      $this->em->persist($newParent); 
      $child->setParent($newParent); 
      $this->em->persist($child); 

      $nbAdded += 2; 
      $this->em->flush(); 
     } 
    } 
} 

因爲我不認爲剩下的將在這裏幫助你這不是我的全部服務,但如果你需要更多的信息問我。

+0

你是什麼意思,它*超載你的服務器*?聽起來並不複雜。 – jeroen

+0

「快速」或「在導入之前在數據上做一些工作」。選擇一個 – Dimi

+0

它需要太多時間來執行並減慢我的服務器。我編輯 –

回答

1

儘管我並沒有提供定量確定程序瓶頸的方法,但我可以提出一些可能會顯着提高性能的指導原則。

  1. 儘量減少數據庫提交的數量。當你寫入數據庫時​​會發生很多事情。最後只能提交一次嗎?

  2. 最小化正在製作的數據庫讀取次數。與前一點類似,從數據庫中讀取數據時會發生很多事情。


如果考慮上述各點後,你仍然有問題,確定哪些SQL的ORM實際上是生成和執行。 ORM工作良好,直到效率成爲問題,需要更多的關注以確保生成最佳查詢。此時,更熟悉ORM和SQL將是有益的。


你似乎沒有處理太多的數據,但如果你是,MySQL只支持讀取CSV文件。

LOAD DATA INFILE語句以非常高的速度從文本文件中讀取行到表中。 https://dev.mysql.com/doc/refman/5.7/en/load-data.html

您可以通過您的ORM訪問此MySQL的具體功能,但如果沒有,你需要寫一些簡單的SQL利用它。由於您需要修改從CSV中讀取的數據,因此可以通過以下步驟非常快速地完成此操作:

  1. 使用LOAD DATA INFILE將CSV讀取到臨時表中。
  2. 根據需要操縱臨時表和其他表中的數據。
  3. 將數據從臨時表中選擇到目標表中。
+0

謝謝你的時間。我最大限度地減少提交數量的問題是,爲了堅持我的孩子,我需要父母已經被堅持。但也許首先讓俱樂部的所有用戶使用兩個陣列,這一個和文件中的一個,會是一個很大的改進。不要爲什麼我沒有想到它,現在看起來很明顯:)。我讀過關於LOAD DATA INFILE的文章,但是因爲我必須先處理數據,所以我先忘了它。但我喜歡將它與臨時表一起使用並在這裏處理數據的想法。我會這樣看。感謝您的幫助 ! –

相關問題