Php 我怎样才能更快地做到这一点?

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

我有一个导入CSV文件的脚本。在我的数据库中,除了其他内容外,还有一个客户列表和一个地址列表。我有一个名为
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”这个词。它给了我找到答案所需的搜索词。