Php 我怎样才能更快地做到这一点?
我有一个导入CSV文件的脚本。在我的数据库中,除了其他内容外,还有一个客户列表和一个地址列表。我有一个名为Php 我怎样才能更快地做到这一点?,php,mysql,performance,Php,Mysql,Performance,我有一个导入CSV文件的脚本。在我的数据库中,除了其他内容外,还有一个客户列表和一个地址列表。我有一个名为customer的表和另一个名为address的表,其中address有一个customer\u id 对我来说重要的一点是不要有任何重复的行。因此,每次导入地址时,我都会执行以下操作: $address = new Address(); $address->setLine_1($line_1); $address->setZip($zip); $address->setC
customer
的表和另一个名为address
的表,其中address
有一个customer\u id
对我来说重要的一点是不要有任何重复的行。因此,每次导入地址时,我都会执行以下操作:
$address = new Address();
$address->setLine_1($line_1);
$address->setZip($zip);
$address->setCountry($usa);
$address->setCity($city);
$address->setState($state);
$address = Doctrine::getTable('Address')->findOrCreate($address);
$address->save();
正如您可能猜到的那样,findOrCreate()
所做的是查找匹配的地址记录(如果它存在),否则只需返回一个新的address
对象。代码如下:
public function findOrCreate($address)
{
$q = Doctrine_Query::create()
->select('a.*')
->from('Address a')
->where('a.line_1 = ?', $address->getLine_1())
->andWhere('a.line_2 = ?', $address->getLine_2())
->andWhere('a.country_id = ?', $address->getCountryId())
->andWhere('a.city = ?', $address->getCity())
->andWhere('a.state_id = ?', $address->getStateId())
->andWhere('a.zip = ?', $address->getZip());
$existing_address = $q->fetchOne();
if ($existing_address)
{
return $existing_address;
}
else
{
return $address;
}
}
这样做的问题是速度太慢。要保存CSV文件中的每一行(转换为不同表上的几个
INSERT
语句),大约需要四分之一秒。我想让它尽可能接近“即时”,因为有时我的CSV文件中有50000多行。我发现,如果我注释掉导入中保存地址的部分,速度会快得多。有没有更快捷的方法?我曾短暂考虑过在其上添加索引,但似乎由于所有字段都需要匹配,因此索引没有帮助。我建议您研究使用加载数据填充将CSV文件加载到MySQL中:
为了更新现有行,您有两个选项<代码>加载数据填充
没有upsert功能(在重复键更新时插入…),但它有一个替换
选项,您可以使用该选项更新现有行,但您需要确保您有一个适当的唯一索引,并且替换实际上只是一个删除
和插入
,这比更新要慢
另一个选项是将CSV中的数据加载到临时表中,然后使用重复键更新时的插入将该表与活动表合并。再次确保您有一个适当的唯一索引,但在这种情况下,您是在执行更新而不是删除,因此应该更快。看来重复检查是使您减速的原因。要找出原因,请找出正在创建的查询原则,并在其上运行EXPLAIN
我猜您需要创建一些索引。搜索整个表可能非常慢,但是向zip添加索引将允许查询只对具有该邮政编码的地址进行完整搜索。EXPLAIN
将能够指导您进行其他优化。这当然不会减少花费在数万次迭代上的所有时间,但是为什么不在每次迭代的DB查询之外管理您的地址呢?总体思路:
获取所有当前地址的列表(将其存储在数组中)
迭代时,检查数组成员资格(校验和[sic]);如果不存在,则将新地址存储在数组中,并将地址保存到数据库中
除非我误解了这个场景,否则这种方式只能在必要时进行插入查询,并且除了第一个查询之外,不需要执行任何选择查询 我最终做的是使用而不是使用findOrCreate()
嗯,这大大提高了性能。您考虑过使用mySQL的原生加载数据填充吗?我不确定它能不能很好地处理现有的地址,但我想这一定是最快的方法之一。那么,“慢”是什么意思?你导入10个地址,需要20秒吗?或者10万,需要一分钟。。。如果看不到在findOrCreate
上实际运行的查询/代码,我们就无法对其工作原理提供那么多反馈。在您匹配所有字段的情况下,索引仍然绝对有用。您是否查看过查询/查询原则?您是否尝试过使用EXPLAIN
分析它们?任何seached列都有索引吗?您还可以使用诸如XDebug或Zend_Debugger之类的探查器来确保导致速度减慢的是真正的数据库,而不是CSV解析本身。这可能是目前为止最好的方法。我可能会这么做。(我说“可能”是因为我已经找到了一个不同的、更简单的解决方案,可能就足够了。)谢谢你给我介绍“upsert”这个词。它给了我找到答案所需的搜索词。