PHP MySQL - 更新6.5m行性能问题

时间:2017-09-06 11:35:08

标签: php mysql performance myisam

我正在使用MySQL表,我需要为每行增加一列中的值,其中超过6.5米。

col类型为varchar,可以包含整数或字符串(即+1)。表格类型为MyISAM

我用PHP尝试过这个:

  $adjust_by = 1;
  foreach ($options as $option) {
      $original_turnaround = $option['turnaround'];
      $adjusted_turnaround = $option['turnaround'];

      if (preg_match('/\+/i', $original_turnaround)) {
        $tmp = intval($original_turnaround);
        $tmp += $adjust_by;
        $adjusted_turnaround = '+'.$tmp;
      } else {
        $adjusted_turnaround += $adjust_by;
      }

      if (!array_key_exists($option['optionid'], $adjusted)) {
        $adjusted[$option['optionid']] = array();
      }

      $adjusted[$option['optionid']][] = array(
        'original_turn' => $original_turnaround,
        'adjusted_turn' => $adjusted_turnaround
      );
  }//end fe options

  //update turnarounds:
  if (!empty($adjusted)) {
    foreach ($adjusted as $opt_id => $turnarounds) {
      foreach ($turnarounds as $turn) {
        $update = "UPDATE options SET turnaround = '".$turn['adjusted_turn']."' WHERE optionid = '".$opt_id."' and turnaround = '".$turn['original_turn']."'";
        run_query($update);
      }
    }
  }

由于显而易见的原因,这种方法存在严重的性能问题。在我的本地开发环境中运行此操作会导致大量错误,并最终导致服务器崩溃。

我需要考虑的另一件事是在生产环境中运行它。这是一个电子商务商店,我不能有像这样的巨大更新锁定数据库或导致任何其他问题。

我找到的一个可能的解决方案是:Fastest way to update 120 Million records

但是创建另一个表会带来它自己的问题。代码库不是很好的状态,类似的查询在这个表的大量地方运行,所以我必须修改大量的查询和文件才能使这种方法有效。

我有什么选择(如果有的话)?

3 个答案:

答案 0 :(得分:6)

您可以使用SQL执行此任务。

  • 使用CAST,您可以将字符串转换为整数。
  • 使用IFSUBSTR,您可以检查字符串是否包含+
  • 使用CONCAT,您将添加(将两个值合并为一个字符串)+到您的计算结果(如果有必要)。

试试这个SQL:

"UPDATE `options` SET `turnaround` = CONCAT(IF(SUBSTR(`turnaround`, 1, 1) = '+', '+', ''), CAST(`turnaround` AS SIGNED) + " + $adjust_by + ") WHERE 1";

答案 1 :(得分:1)

你不能只说

UPDATE whatevertable SET whatever = whatever + 1

尝试一下,看看,我很确定它会起作用!

编辑:你有字符串或整数?您的数据库设计存在缺陷,这可能不起作用,但如果您的数据库设计更加严格,那么这将是正确的答案。

答案 2 :(得分:0)

你可能没有,但需要这个'复合'索引(按任意顺序):

INDEX(optionid, turnaround)

请提供SHOW CREATE TABLE

另一个轻微的性能提升是在更新循环之前显式LOCK TABLE WRITE。然后UNLOCK。注意:这仅适用于MyISAM。

使用InnoDB会好得多。