Domanda

Mi chiedo se valga la pena il tempo del server durante l'aggiornamento di un record per recuperare il record esistente, scorrere i campi controllando le modifiche e inserendo solo i campi modificati nella query di aggiornamento? (Sto usando MySQL & amp; PHP.)

Il motivo principale per eseguire questa operazione è ridurre la dimensione della query di aggiornamento ai fini del registro delle modifiche. Normalmente la query potrebbe avere 15 campi, ma solo 2 campi vengono effettivamente modificati. Questa query può quindi essere utilizzata anche per la registrazione poiché conterrà solo i campi modificati e quindi è più facile da analizzare.

La mia preoccupazione è il tempo necessario per recuperare il record esistente.

O c'è un modo per recuperare da MySQL quali campi ha aggiornato?

È stato utile?

Soluzione

Penso che valga la pena cambiare - ma probabilmente non vale la pena fare una selezione prima di inserire.

Aggiorna solo i campi che sono stati modificati, fa parte dell'operazione della mia classe DbEntity che segue un modello activerecord. Per fare questo costa poco, perché tengo il record corrente e i record originali, semplicemente copiando ogni volta che viene caricato un record.

I motivi sono la brevità, non proprio le prestazioni. Inoltre, è possibile verificare la presenza di modifiche simultanee aggiungendo una clausola where sul vecchio valore dei campi aggiornati e generare l'errore appropriato.

Nel metodo di scrittura / aggiornamento:

$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);

Nel metodo di caricamento

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

Altri suggerimenti

Al livello più elementare, se sto leggendo correttamente la tua domanda, generalmente non vuoi aggiornare ciecamente l'intero record nel caso in cui un altro utente abbia già aggiornato parti di quel record che non hai effettivamente modificato. Dovresti ripristinare ciecamente e inutilmente i loro aggiornamenti.

Credo che il tuo attuale algoritmo possa portare a scritture sporche, se hai intenzione di leggere la corrente una volta per l'aggiornamento, consentire gli aggiornamenti da effettuare in memoria, quindi rileggere il record per permetterti di capire quali campi sono stati aggiornato. Cosa succede se un altro utente aggiorna quel record alle tue spalle, portando il tuo algoritmo a credere che tu sei stato tu ad aggiornare quel campo? Ma soprattutto, non dovresti leggere ogni record due volte per eseguire un singolo aggiornamento.

Se i tuoi dati non causano spesso conflitti, potresti trarre vantaggio dalla lettura del blocco ottimistico, anche se non decidi di implementarli.

Qui abbiamo implementato un metodo per aggiungere un timestamp di aggiornamento o una colonna di numero di aggiornamento incrementale alla tabella. Quindi nella tua sandbox / memoria puoi tenere traccia di quali campi hai modificato (oldvalue / newvalue) e puoi inviare liberamente il tuo aggiornamento SQL per quel record per quei campi, " UPDATE ... WHERE UPDATENUM = the-original- numero " (o WHERE UPDATETS = the-original-timestamp), assicurandoti che il tuo SQL di aggiornamento aumenti anche UPDATENUM o UPDATETS, come appropriato. Se il record interessato da quell'aggiornamento SQL è 0, sai che qualcun altro ha già modificato quel record in background e ora hai un conflitto. Ma almeno non hai sovrascritto le modifiche di qualcun altro e puoi quindi rileggere i nuovi dati o chiedere al tuo utente di risolvere il conflitto.

Il punto più lento nella tua applicazione sarà sempre l'accesso al tuo database, quindi se puoi accelerarlo, è una buona idea. Detto questo, dipende davvero da quanto sono grandi il tuo database, i tuoi record e quanto è probabile che crescano, se valga la pena di verificare a livello di codice se gli articoli sono stati aggiornati. Se il tuo database è piccolo e l'accesso è già abbastanza rapido, potrebbe non valere la pena. Ma se la velocità può essere migliorata e ti dà un ulteriore vantaggio per la tua registrazione, allora provaci.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top