【问题标题】:SQL - Fastest way to do an UPDATESQL - 执行 UPDATE 的最快方法
【发布时间】:2014-09-12 10:17:04
【问题描述】:

我在 PHP/MySQL 中创建了一个小程序来更新数据库中的表,我想知道在 UPDATE 语句中引入条件会如何改变它的性能。

现在我正在对表的每条记录执行 UPDATE,忽略了我要更新的字段已经计算和更新的事实:

mysql_query("UPDATE matches SET delta=".$delta." WHERE id=".$idp."");

其中$delta 是先前计算的PHP 变量,id 是表的唯一键。

插入条件以确定增量字段是否已在表中计算/更新,或者是否仍设置为 0(其默认值),在执行速度方面是否有任何差异?

mysql_query("UPDATE matches SET delta=".$delta." WHERE id=".$idp." and delta=0");

添加delta=0 条件有什么改进吗?

总结我的问题:由于delta=0 条件为假而未执行表上的写操作时,UPDATE 是否更快?我的表有大约 10k 条记录。

提前谢谢并原谅我糟糕的英语! ;-) 安德烈亚

【问题讨论】:

  • 取决于您的数据和索引。

标签: php mysql sql sql-update


【解决方案1】:

如果您要进行这样的多次更新,那么通常我会建议您进行 INSERT,但在 id 已经存在时使用重复键条件进行更新。这样,您可能会执行一个 SQL 查询,而不是对表中的每条记录执行一个查询。

mysql_query("INSERT INTO matches (id, delta)
VALUES
($idp1, $delta1),
($idp2, $delta2),
($idp3, $delta3),
($idp4, $delta4)
ON DUPLICATE KEY UPDATE delta=VALUES(delta)
");

编辑

这是我在进行多次插入/更新时有时会使用的一个 php 类(这里是稍微简化的版本)

<?php

class table_process
{

    var $link;
    var $row_array = array();
    var $field_name_store = '';
    var $table_name = '';
    var $record_count = 0;
    var $update_clause = '';
    var $rows_to_process = 255;

    function __CONSTRUCT($link, $table_name, $update_clause = '')
    {
        $this->link = $link;
        $this->table_name = $table_name;
        $this->update_clause = $update_clause;
    }
    function __DESTRUCT()
    {
        if (count($this->row_array) > 0)
        {
            $this->process_rows();
        }
    }
    function field_names($in_field_names)
    {
        $this->field_name_store = "(`".implode("`,`", $in_field_names)."`)";
    }
    function record_count()
    {
        return count($this->record_count);
    }
    function make_row($in_row)
    {
        $ret = true;
        foreach($in_row AS &$in_field)
        {
            $in_field = (($in_field == null) ? "NULL" : "'".mysql_real_escape_string($in_field, $this->link)."'");
        }
        $this->record_count++;
        $this->row_array[] = "(".implode(",", $in_row).")";
        if (count($this->row_array) > $this->rows_to_process)
        {
            $ret =  $this->process_rows();
        }
        return $ret;
    }
    function process_rows()
    {
        $ret = true;
        $sql = "INSERT INTO ".$this->table_name." ".$this->field_name_store." VALUES ".implode(",", $this->row_array)." ".$this->update_clause;
        if (!mysql_query($sql, $this->link))
        {
            $ret = false;
        }
        $this->row_array = array();
        return $ret;
    }
    public function set_rows_to_process($rows_to_process)
    {
        if (is_numeric($rows_to_process) and intval($rows_to_process) > 0)
        {
            $this->rows_to_process = $rows_to_process;
        }
    }
}

?>

然后你可以像下面这样使用它:-

$ProcessMatches = new table_process($link, 'matches', ' ON DUPLICATE KEY UPDATE delta=VALUES(delta)', true);
$ProcessMatches->field_names(array('id', 'delta'));

$ProcessMatches ->make_row(array('id'=>$id1, 'delta'=>$delta1));
$ProcessMatches ->make_row(array('id'=>$id2, 'delta'=>$delta2));
$ProcessMatches ->make_row(array('id'=>$id3, 'delta'=>$delta3));
$ProcessMatches ->make_row(array('id'=>$id4, 'delta'=>$delta4));
$ProcessMatches ->make_row(array('id'=>$id5, 'delta'=>$delta5));
$ProcessMatches ->make_row(array('id'=>$id6, 'delta'=>$delta6));

unset($ProcessMatches);

该类采用连接链接和表名/列名,以及更新子句(如果需要)。

您插入的每一行都由该类获取并为插入而构建。一旦准备好插入 255 行,它就会插入它们并擦除存储它们的数组。完成后,取消设置触发 __DESTRUCT 方法的对象,该方法执行最终插入。

【讨论】:

  • 我的 $idp 和 $delta 变量是 10.000+ 这不是问题吗?
  • 可能,但是 10000 多个单独的更新语句将非常耗时。我倾向于一次将它们批处理到大约 250 个。我会用一些我有时使用的代码来更新答案。
  • 谢谢@Kickstart;但仍然是我的最后一个问题:由于 delta=0 条件为假而未执行表上的写操作时,UPDATE 是否更快?
  • 不确定更新。它将强制检查每条记录。这可能会加快速度,但我怀疑这将取决于有多少潜在的更新确实会导致更新。如果您将所有更新插入到临时表中,然后基于连接进行更新,但检查值是否已作为连接条件的一部分发生更改,则检查可能会改善情况。但这只是我对事情如何运作的感觉,我还没有做过任何检查。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-02
  • 2015-05-08
  • 1970-01-01
  • 1970-01-01
  • 2018-07-26
相关资源
最近更新 更多