10

我想知道在更新记录以检索现有记录时是否值得服务器时间,循环检查更改的字段并仅将更改的字段放入更新查询中?(我正在使用 MySQL 和 PHP。)

这样做的主要原因是为了减少更新查询的大小以用于更改日志。通常查询可能有 15 个字段,但实际上只有 2 个字段被更改。这个查询也可以用于记录,因为它只包含更改的字段,因此更容易解析。

我担心的是检索现有记录所需的时间。

或者有没有办法从 MySQL 中检索它更新了哪些字段?

4

3 回答 3

3

我认为值得改变 - 但可能不值得在插入之前进行选择。

我只更新已更改的字段,它是我的 DbEntity 类操作的一部分,它遵循 activerecord 模式。这样做几乎不需要额外的费用,因为我持有当前记录和原始记录 - 只需在加载记录时进行复制。

原因很简单——不是真正的表现。您还可以通过在更新字段的旧值上添加 where 子句来检查并发修改并引发相应的错误。

在写入/更新方法中:

$s1 = "";

foreach ($this->record as $key => $value)
{
    // only update fields that have been changed
    if ($value != $this->orig_record[$key])
    {
        $s1 .= $comma."`$key`='".mysql_real_escape_string($value)."'";
        $comma = ", ";
    }
}

$query = "UPDATE ".$this->table." SET $s1 where {$this->id_field}='".$this->get_keyfield()."'";
$query .= $this->extra_sql_update;
mysql_query($query);

$ar = mysql_affected_rows();
//
// the number of affected rows is actually those changed by the update operation, which will 
// either be zero, or 1. If the query affects more than one row then we have a problem.
if ($ar < 0 || $ar > 1)
{
    cbf_error("cbf_dbentity: {$this->table} :: only one row (not $ar) must be affected by an insert operation. $query",
      E_USER_ERROR);
}
else
{
    $new_id = $this->get_keyfield();

    GlobalEventBus::notify_all(new AuditLogSQL($this->table, "update", $query));

}

$this->orig_record = Array();

foreach ($this->record as $key => $value)
    $this->orig_record[$key] = $value;


//
// sanity check - ensure that what we have just written is actually there.

$this->load($new_id);

foreach ($this->orig_record as $key => $value)
    if (trim($this->record[$key]) != trim($value) 
        && (!$this->record[$key] == "0" && $value=""))
        cbf_error("cbf_dbentity: {$this->table} :: record differs during write after reload: field $key was \"$value\", after write it is now \"".
              $this->record[$key]."\"",E_USER_ERROR);

在加载方法中

$this->orig_record = Array();
foreach ($this->record as $key => $value)
    $this->orig_record[$key] = $value;
于 2009-01-20T00:06:05.893 回答
2

在最基本的层面上,如果我没看错你的问题,你通常不想盲目地更新整个记录,以防另一个用户已经更新了你实际上没有更改的记录的部分。您会盲目且不必要地恢复他们的更新。

我相信您当前的算法可能会导致脏写,如果您要读取当前一次进行更新,请允许在内存中进行更新,然后再次读取记录以让您确定哪些字段已更新。如果另一个用户在您背后更新了该记录,导致您的算法相信是更新该字段的人,会发生什么?但首先,您不必为了执行一次更新而读取每条记录两次。

如果您的数据不经常导致冲突,您可能会从阅读乐观锁定中受益,即使您不选择实现它。

我们在这里实现了一种方法,您可以将更新时间戳或增量更新编号列添加到表中。然后在您的沙箱/内存中,您可以跟踪您修改了哪些字段(旧值/新值),并且您可以自由地为这些字段的该记录发出更新 SQL,“UPDATE...WHERE UPDATENUM=the-original-number "(或 WHERE UPDATETS=the-original-timestamp),确保您的更新 SQL 也酌情增加 UPDATENUM 或 UPDATETS。如果受该更新 SQL 影响的记录为 0,则您知道其他人已经在后台修改了该记录,并且您现在有冲突。但至少您没有覆盖其他人的更改,然后您可以重新读取新数据或让您的用户解决冲突。

于 2009-01-20T00:37:30.353 回答
1

应用程序中最慢的点总是数据库访问,所以如果你能加快速度,这是个好主意。也就是说,这实际上取决于您的数据库和记录有多大,以及它们可能增长到多大,是否值得以编程方式检查项目是否已更新。如果您的数据库很小并且访问速度已经很快,那么可能不值得花时间。但是,如果可以提高速度,并为您的日志记录带来额外的好处,那就去吧。

于 2009-01-20T00:04:46.833 回答