Вы обновляете только измененные поля или все поля? - PullRequest
9 голосов
/ 20 января 2009

Мне интересно, стоит ли серверное время при обновлении записи для извлечения существующей записи, циклически просматривая поля, проверяя наличие изменений, и помещая только измененные поля в запрос на обновление? (Я использую MySQL и PHP.)

Основная причина для этого - уменьшить размер запроса на обновление для целей журнала изменений. Обычно запрос может иметь 15 полей, но только 2 поля на самом деле изменяются. Этот запрос затем можно также использовать для ведения журнала, поскольку он будет содержать только измененные поля и, следовательно, его легче проанализировать.

Меня беспокоит время, необходимое для извлечения существующей записи.

Или есть способ извлечь из MySQL какие поля он обновил?

Ответы [ 3 ]

3 голосов
/ 20 января 2009

Я думаю, что это стоит изменить - но, вероятно, не стоит делать выбор перед вставкой.

Я только обновляю измененные поля, это часть работы моего класса 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;
2 голосов
/ 20 января 2009

На самом базовом уровне, если я правильно читаю ваш вопрос, вы обычно не хотите вслепую обновлять всю запись в случае, если другой пользователь уже обновил части этой записи, которые вы на самом деле не изменили. Вы бы слепо и без необходимости возвращали свои обновления.

Я полагаю, что ваш текущий алгоритм может привести к грязным записям, если вы собираетесь прочитать текущее для обновления один раз, разрешить обновления в памяти, а затем снова прочитать запись, чтобы вы могли выяснить, какие поля были обновлено. Что произойдет, если другой пользователь обновит эту запись за вашей спиной, заставив ваш алгоритм полагать, что вы были тем, кто обновил это поле? Но прежде всего вам не нужно читать каждую запись дважды, чтобы выполнить одно обновление.

Если ваши данные не часто приводят к конфликтам, вы можете извлечь пользу из чтения об оптимистической блокировке, даже если вы не решите ее реализовать.

Мы реализовали здесь один метод, с помощью которого вы добавляете отметку времени обновления или добавочный столбец числа обновлений к вашей таблице. Затем в своей песочнице / памяти вы можете отслеживать, какие поля вы изменили (oldvalue / newvalue), и вы можете свободно выдавать обновляющий SQL для этой записи для этих полей: "UPDATE ... WHERE UPDATENUM = номер-оригинала-номера" "(или WHERE UPDATETS = the-original-timestamp), чтобы убедиться, что ваш SQL обновления также увеличивает UPDATENUM или UPDATETS, в зависимости от ситуации. Если записи, затронутые этим обновлением SQL, равны 0, вы знаете, что кто-то уже изменил эту запись в фоновом режиме, и у вас теперь есть конфликт. Но, по крайней мере, вы не перезаписали чужие изменения, и затем вы можете перечитать новые данные или разрешить пользователю разрешить конфликт.

1 голос
/ 20 января 2009

Самым медленным моментом в вашем приложении всегда будет доступ к базе данных, поэтому, если вы можете ускорить его, это хорошая идея. Тем не менее, это действительно зависит от того, насколько велики ваша база данных и записи, и насколько велики они могут вырасти, от того, стоит ли пытаться программно проверить, обновились ли элементы. Если ваша база данных небольшая и доступ к ней уже достаточно быстрый, это может не стоить потраченного времени. Но если скорость может быть улучшена и это дает вам дополнительное преимущество при ведении журнала, тогда сделайте это.

...