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

PHP MySQL-更新650万行的性能问题,php,mysql,performance,myisam,Php,Mysql,Performance,Myisam,我正在处理一个MySQL表,我需要为每行增加一列中的值,其中有超过6.5m的行 列类型为varchar,可以包含整数或字符串(即+1)。表格类型为MyISAM 我曾尝试使用PHP实现这一点: $adjust_by = 1; foreach ($options as $option) { $original_turnaround = $option['turnaround']; $adjusted_turnaround = $option['turnaround']

我正在处理一个MySQL表,我需要为每行增加一列中的值,其中有超过6.5m的行

列类型为
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);
      }
    }
  }
由于明显的原因,这种方法存在严重的性能问题。在我的本地开发环境中运行此操作会导致许多错误,并最终导致服务器崩溃


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

我发现一个可能的解决方案是:

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

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

你就不能说吗

更新whatevertable SET whatever=whatever+1

试试看,我敢肯定它会成功的


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

您可以使用SQL完成此任务

  • 使用,可以将字符串转换为整数
  • 使用,您可以检查字符串是否包含
    +
  • 使用,您将在计算结果中添加(将两个值合并为一个字符串)
    +
    (如果需要)
请尝试以下SQL:

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

您可能没有但需要此“复合”索引(按任意顺序):

请提供
SHOW CREATE TABLE

另一个轻微的性能提升是在更新循环之前显式地
锁定表写入。然后解锁。注意:这仅适用于MyISAM


你可以更好地使用NYNDB。

“我需要考虑的是,当这是在生产环境中运行的时候。这是电子商务商店,我不能像这样大的更新锁定数据库或引起任何其他问题。”MyISAM引擎将在更新或插入时锁定表。您应该考虑将表转换为NYNDB引擎。此引擎未使用更新或插入锁定表。表是否已正确索引?也许简单的索引可以加快速度。不要用PHP运行密集型任务。您可能会遇到最大超时问题,而且PHP不是为CPU密集型任务而设计的。您可以使用python来完成此任务。@RaymondNijland是的,您完全正确,但是,更改表类型会对该表与另一个表连接的其他查询产生任何影响吗?@user254153您是否建议切换到python,因为您认为与PHP相比,它对于CPU密集型任务“更好”?请更新你的知识库,你的建议是不好的,不正确的,基于你的个人喜好,而不是事实。此外,这不是CPU密集型任务。是的,我知道,如果DB和代码库设计得当,这将是一个完美的解决方案。可悲的是,这就是我所继承的。到处都是主要的设计问题=主要的头痛…“继承”意味着您需要在继续之前进行清理。这并不意味着你会被糟糕的设计所困扰。太好了,可以了。你能解释一下这到底是怎么回事吗?我的SQL知识有点有限,我不能完全理解它。谢谢。@Neodan 1在哪里?您可以忽略这一点,因为它总是正确的,这是从等式中删除PHP或任何其他语言的正确答案。它将文本列中的值转换为整数,递增并保存。这基本上是一个很好的修复糟糕的数据库模式+从我这里得到1分!谢谢@Neodan的解释,我正要问一下
WHERE 1
。这个因素是如何影响它的?这指的是
IF(SUBSTR)
是真的吗?@MP_Webby no,
其中1
只是意味着MySQL必须从表中获取所有记录。这是提高性能的老把戏,因为如果您的查询没有
WHERE
部分,那么MySQL会自行添加它。
INDEX(optionid, turnaround)