PHP检查行是否存在的最有效方法

时间:2016-04-12 12:58:00

标签: php mysql doctrine

考虑下表

+-------------+---------+------+-----+---------+----------------+
| Field       | Type    | Null | Key | Default | Extra          |
+-------------+---------+------+-----+---------+----------------+
| id          | int(11) | NO   | PRI | NULL    | auto_increment |
| date        | date    | NO   |     | NULL    |                |
| sku         | varchar(10)    |     |         | NULL           |         
| impressions | int(11) | NO   |     | NULL    |                |
| sales       | int(11) | NO   |     | NULL    |                |
+-------------+---------+------+-----+---------+----------------+

每天从批量下载前几天的销售记录中填充该表。

每天下载不仅包含前几天的销售数据,还包含过去90天的所有数据(可能的50k +记录)。

然而,由于我们无法控制的事项,前几天的数据可能会因原始插入而发生变化,例如

第1天。

Date: 2015-01-01
SKU:  ABCD
Impressions:  100
Sales: 0

第2天。

Date: 2015-01-01
SKU:  ABCD
Impressions:  100
Sales: 3

Date: 2015-01-02
SKU:  ABCD
Impressions:  105
Sales: 0

因此,对于来自数据下载的任何给定记录,它可能是

a)已经看过和以前一样 - 忽略 b)新增 - 添加到数据库 c)已经看过但新数据 - 更新

可以通过检查每一行来解决这个问题

while (!$file->eof()) {
      $row = $file->fgets();
      $data = explode("\t", $row);
      $sku = $data[0];
      $date = $data[1];
      $impressions = $data[2];
      $sales = $data[3];
      $order = $em->getRepository('Orders')->findOneBy(['sku' => $sku, 'date' => $date]);
      if($order && $order->getImpressions() != $impressions && $order->getSales() != $sales) {
            $order->setImpressions($impressions);
            $order->setSales($sales);               
      } else {
        ... create new model
      }
      $em->persist($order);
}

然而,具有更新数据的行将是最小的,并且对每一行进行选择将意味着由于行的数量,该作业将非常慢。

所以我的问题是可以使用哪些模式尽可能有效地解决这个问题?

欢迎任何想法

2 个答案:

答案 0 :(得分:2)

我建议您使用新下载的数据完全替换之前的90天数据。

推理很简单:

  • 执行此操作的处理时间非常简单。 50,000行在数据库方面很小。即使它是一百万行,我也许会这样做。
  • 尝试仅替换更改的行很复杂,可能会引入错误。

答案 1 :(得分:1)

当您说“与以前相同”时,似乎密钥为datesku(合并),销售和展示次数是可以更新的字段。如果这是正确的,那么在MySQL中执行此操作的最有效方法是使用INSERT ... ON DUPLICATE KEY UPDATE ...查询:

  1. datesku列上创建唯一键。

  2. 在您的php脚本中预先解析文件中的所有数据(或者如果您愿意,可以批量执行)。

  3. 运行与此类似的查询(替换步骤1中已解析值的实际数据):

    INSERT INTO
        mytable (`date`, sku, impressions, sales)
    VALUES
        ('2015-01-01', 'ABCD', 100, 3),
        ('2015-01-02','ABCD', 100, 3),
        ...
    ON DUPLICATE KEY UPDATE
        impressions = VALUES(impressions),
        sales = VALUES(sales)
    
  4. 几点说明:

    • 查看documentation了解此语法
    • 如果包含上一日期记录的第二天的数据更新是补充的,您可以sales = sales + VALUES(sales)但我不认为你是这种情况