Ottimizzazione del database rispetto alla leggibilità

-1

Sto lavorando su un codice che controlla la presenza di alcuni invarianti nel database. Ad esempio, per verificare che un elemento non venga ripetuto, il codice verifica un errore del database poiché l'invariante è codificato a livello di database.

Fondamentalmente per far rispettare l'unicità per un determinato set di chiavi il codice verifica l'errore:

if (sqlError = "name_age") { // name+age are non unique cannot insert
  throw error("no users with same name and age allowed")
}

Per me è stato un po 'illeggibile, soprattutto perché deve essere letto insieme alla configurazione del database, inoltre, non può essere testato senza un mock o colpendo il db stesso. Quello che vorrei fare è:

if (countWithNameAndAge(name, age) == 1) {
  throw error("no users with same name and age allowed")
}

Non solo questo è più immediatamente leggibile, ma posso consentire a 2 o 3 persone con lo stesso nome ed età senza evolvere il database o aggiungere colonne.

L'unico inconveniente è che questo potrebbe essere più lento .

È vero che il mio approccio potrebbe essere più lento? È davvero più leggibile?

    
posta gurghet 07.06.2017 - 15:44
fonte

2 risposte

1

Prestazioni rispetto alla leggibilità

Molto probabilmente, il singolo INSERT non sarà significativamente più veloce di una% intelligenteLOCK - FETCH - INSERT - UNLOCK sequenza, perché l'indice UNIQUE impone le stesse operazioni, e il embedded INSERT dovrebbe essere più veloce di% co_de standalone. Ma se le prestazioni sono importanti per te, dovresti condurre un benchmark. La ricerca dell'indice per i record esistenti e l'inserimento dei dati in presenza dell'indice (dovendo aggiornare l'indice) sono le operazioni costose qui.

Maintainability

Il confronto tra la variabile di errore SQL e una stringa è un horror di mainenance. Sarebbe meglio se il codice di ritorno dell'istruzione INSERT desse già un'indicazione su cosa è andato storto, in modo tale che possa essere valutato. Questo sarebbe il mio approccio preferito (per mantenerlo semplice).

Se ciò non è possibile, il confronto tra il testo dell'errore e una costante di stringa potrebbe essere un compromesso, come suggerito da @TimothyTruckle.

Anche il fatto di attenersi a un singolo INSERT potenzialmente in errore ha il vantaggio di non distribuire l'implementazione del requisito di unicità a più livelli. A rigor di termini, con il singolo INSERT , questo invariante essenziale è garantito dall'indice INSERT , e il messaggio di errore separato è semplicemente gradevole all'utente.

Modello dati

Come suggeriscono @ErikEidt e @RSahu, UNIQUE non è la scelta migliore qui. Non dovrebbe essere memorizzato e non è adatto per il controllo dei duplicati il più delle volte.

    
risposta data 07.06.2017 - 19:44
fonte
1
if (countWithNameAndAge(name, age) == 1)

deve passare attraverso ogni elemento nel database per ottenere un conteggio. Puoi cambiarlo in:

if (hasNameAndAge(name, age))

Questo ritornerà alla prima occorrenza di un oggetto con il nome e l'età indicati, e quindi, sarà un po 'più veloce. Tuttavia, si perde la flessibilità di poter consentire a più di 3 persone con lo stesso nome ed età. Se questa flessibilità è indispensabile, puoi modificare hasNameAndAge per aggiungere anche un conteggio.

if (hasNameAndAge(name, age, MAX_COUNT))

Questo ritornerà con true non appena trova MAX_COUNT numero di elementi.

Detto questo, mi chiedo. Dovresti preoccuparti delle conseguenze delle prestazioni nel rilevare i duplicati? Qual è la percentuale di volte che ti aspetti che tu / i tuoi utenti stiate tentando di aggiungere duplicati o duplicati? Se la percentuale di volte che si tenta di aggiungere duplicati è piccola, il problema di prestazioni nel rilevare i duplicati è discutibile.

Sembra che sia necessario ottimizzare il hasNameAndAge , indipendentemente dalla versione scelta, quando si prevede che restituisca false se la percentuale di volte che si tenta di aggiungere duplicati è piccola.

    
risposta data 07.06.2017 - 17:19
fonte