【问题标题】:Speeding up a simple UPDATE query on a huge table加快对大表的简单 UPDATE 查询
【发布时间】:2015-10-09 15:55:07
【问题描述】:

这是我的桌子:

+----------+--------------+------+-----+---------+-------+
| Field    | Type         | Null | Key | Default | Extra |
+----------+--------------+------+-----+---------+-------+
| CLID     | int(11)      | NO   | MUL | NULL    |       |
| calldate | datetime     | YES  | MUL | NULL    |       |
| src      | varchar(20)  | YES  |     | NULL    |       |
| dst      | varchar(20)  | YES  |     | NULL    |       |
| billsec  | varchar(10)  | YES  |     | NULL    |       |
| duration | time         | YES  |     | NULL    |       |
| debt     | float        | YES  | MUL | NULL    |       |
| region   | varchar(255) | YES  |     | NULL    |       |
| uniqueid | varchar(20)  | NO   | PRI | NULL    |       |
+----------+--------------+------+-----+---------+-------+

它有超过 490,328 条记录。我必须更新此表中的每条记录。这是查询(我在 PHP 中使用 mysqli):

UPDATE `All` 
SET `debt` = '$debt', `region` = '$region' 
WHERE `uniqueid` = $uid;

不幸的是,执行单个查询需要大约 1.4519529342651 秒。有什么办法可以加快速度吗?

【问题讨论】:

  • 你有uniqueid 的索引吗?
  • @JuanCarlosOropeza 它是一个主键,它是一种索引类型,对吧?
  • 您可以通过 uniqueid 范围对表进行分区,因此查询不必查看扫描所有行。此外,您可以尝试一次性更新所有这些记录,其中 dbt 和 region 更改为相同的值,而不是单独更新每条记录。
  • 抱歉错过了。如果您必须更新每条记录,如果您再次创建表CREATE TABLE 'All' AS Select * FROM WhereYouHaveTheData 可能很容易。
  • 其他选项在更新过程中禁用debtregion 上的任何索引。因为每次更新后索引都会重建。然后在最后再次启用。

标签: mysql sql optimization query-optimization


【解决方案1】:

1.45 秒更新一条记录是非常糟糕的表现,而且非常出乎意料。您的查询打算使用主键更新单行。您不应该注意到时间量。

但是,由于条件的表达方式,引擎不能为此查询使用主键索引。让我们更详细地看一下查询:

UPDATE `All` 
SET `debt` = '$debt', `region` = '$region' 
WHERE `uniqueid` = $uid;
-------------------^

除非$uid 在值中有引号包含,否则它会被视为字符串以外的东西。所以,如果你传入“1”,那么你有一个与字符串相比的整数。这可以防止使用索引。哎呀。

我的第一个建议是使用参数来修复您的查询。除此之外,请在:

UPDATE `All` 
SET `debt` = '$debt', `region` = '$region' 
WHERE `uniqueid` = ''$uid'';

如果uniqueid 实际上看起来像一个数字,请考虑将其存储为数字而不是字符串。

当然,其他事情也可能出错,例如:

  • 其他查询可能会锁定表。
  • 您可以从冷启动测试查询,所有后续查询都将非常快速。
  • 表中的触发器可能非常缓慢。

【讨论】:

  • @user3125731 。 . .现在需要多长时间?
  • 目前大约需要 0.00058412551879883 秒,这已经足够了。也就是说,在按照您的建议修改查询并从 CLIDcalldatedebt 列中删除索引之后。
  • @user3125731 。 . .说 99.96% 的速度提升听起来更戏剧化 ;)
  • 我的是一个整数值,去掉了引号,改进令人难以置信。谢谢
【解决方案2】:

编辑:在执行我的建议之前,我肯定会尝试 Gordon Linoff 的解决方案,因为它很有意义(在 where 子句中传递的值周围缺少引号)。

您的 MySQL 数据库是否与您的 PHP 服务器相距很远?这可以解释糟糕的表现。

如果您直接在 phpMyAdmin 界面上执行此操作时性能更好,我会尝试同时传递多个更新(请参阅http://php.net/manual/en/mysqli.quickstart.multiple-statement.php)。

这样(这不是实际代码,只是为了让您了解我的意思):

$i = 0;
$query = '';

while (yourcondition){

  if ($i < 50){
    // Change values of your $dbt, $region and $uid varialbes here and concatenate the new statement to the existing $query var
    $query .='UPDATE `All` 
      SET `debt` = '$debt', `region` = '$region' 
      WHERE `uniqueid` = $uid; '
  } else {
    // Execute your update on your mysqli object then empty your $query and set $i to 0
    $mysqli->query($query);
    $query = '';
    $i = 0;
  }

  $i++;
}

从 50 开始,看看它是否提高了性能,如果有,就增加它。

【讨论】:

    【解决方案3】:

    您应该在 mysql 中为特定的更新列添加索引,并在编程时放置包含这些 id 的数组。 最后用 ids IN 更新单个命令。

    希望上面是明确的!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-07-31
      • 1970-01-01
      • 1970-01-01
      • 2011-06-20
      • 2015-12-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多