PHP MySQL - 更新 650 万行性能问题

PHP MySQL - Update 6.5m rows performance issues

我正在使用 MySQL table 并且我需要在每一行的一列中递增一个值,其中超过 6.5m。

col 类型为 varchar,可以包含整数或字符串(即 +1)。 table 类型是 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

但是创建另一个 table 也有其自身的问题。代码库状态不佳,类似查询 运行 在这个 table 的很多地方,所以我必须修改大量查询和文件才能使这种方法起作用。

我有哪些选择(如果有的话)?

你就不能直接说吗

UPDATE whatevertable SET whatever = whatever + 1?

试试看,我很确定它会成功!

编辑:你有字符串或整数?您的数据库设计有缺陷,这可能行不通,但如果您的数据库设计更严格,这将是正确的答案。

您可以使用 SQL 完成此任务。

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

试试这个 SQL:

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

您可能没有,但需要这个 'composite' 索引(按任一顺序):

INDEX(optionid, turnaround)

请提供SHOW CREATE TABLE.

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

使用 InnoDB 会更好。