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 完成此任务。
试试这个 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 会更好。
我正在使用 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 完成此任务。
试试这个 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 会更好。