SQL - 执行 UPDATE 的最快方法
Posted
技术标签:
【中文标题】SQL - 执行 UPDATE 的最快方法【英文标题】:SQL - Fastest way to do an 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 条记录。
提前谢谢并原谅我糟糕的英语! ;-) 安德烈亚
【问题讨论】:
取决于您的数据和索引。 【参考方案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 是否更快? 不确定更新。它将强制检查每条记录。这可能会加快速度,但我怀疑这将取决于有多少潜在的更新确实会导致更新。如果您将所有更新插入到临时表中,然后基于连接进行更新,但检查值是否已作为连接条件的一部分发生更改,则检查可能会改善情况。但这只是我对事情如何运作的感觉,我还没有做过任何检查。以上是关于SQL - 执行 UPDATE 的最快方法的主要内容,如果未能解决你的问题,请参考以下文章
Oracle:使用 SQL 或 PL/SQL 提取文件扩展名的最快方法