我解释一下,我有一个Symfony2项目,我需要通过我的数据库中的csv文件导入用户。在MySQL中导入数据之前,我必须对数据做一些工作。我为此创建了一个服务,一切正常,但是如果我将整个文件都给它,那么执行和减慢我的服务器需要花费太多时间。我的文件通常在500到1500行之间,我必须将文件拆分成~200行文件并逐个导入。
我需要处理已经存在于文件和/或数据库中的相关用户。相关用户通常是孩子的父母。
这是我的简化代码:
$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 :(得分:1)
虽然我没有采用定量方法来确定程序中的瓶颈,但我可以提出一些可能会显着提高其性能的指南。
最大限度地减少您正在进行的数据库提交的数量。写入数据库时会发生很多事情。是否可以在结束时只提交一次?
最大限度地减少您正在进行的数据库读取次数。与前一点类似,当您从数据库中读取时会发生很多事情。
如果在考虑上述几点后仍然存在问题,请确定ORM实际生成和执行的SQL。 ORM工作得很好,直到效率成为一个问题,并且需要更多的关注来确保生成最佳查询。此时,更熟悉ORM和SQL将是有益的。
您似乎没有使用太多数据,但如果您使用,MySQL本身就支持读取CSV文件。
LOAD DATA INFILE语句以非常高的速度将文本文件中的行读取到表中。 https://dev.mysql.com/doc/refman/5.7/en/load-data.html
您可以通过ORM访问此MySQL特定功能,但如果没有,则需要编写一些纯SQL来使用它。由于您需要修改从CSV中读取的数据,因此您可以通过以下步骤非常快速地执行此操作: