DRY con SQL dinamico e istruzioni preparate

4

Quando si tratta di dati, si scopre che, in sostanza, lo stesso codice viene ripetuto in varie incarnazioni:

-- MySQL:
CREATE TABLE users (
    id int NOT NULL auto_increment PRIMARY KEY,
    name varchar(255) NOT NULL,
    email varchar(255) NOT NULL,
    UNIQUE KEY akUser (email)
)

// PHP
class User extends DBModel {
    protected $id;
    protected $name;
    protected $email;

    function __construct() {
        $this->queries = array(
            'getById' => 'SELECT id, name, email FROM users WHERE id = :id',
            'addUser' => 'INSERT INTO users (name, email) VALUES (:name, :email)',
            'updateUser' => 'UPDATE users SET name = :name, email = :email WHERE id = :id',
        );
    }

    public function loadById($id) {
        $stmt = $this->getPreparedStatement('getById');
        $stmt->bindValue(':id', $id);
        $stmt->execute();
        $stmt->setFetchMode(PDO::FETCH_INTO, $this);
        return $stmt->fetch();
    }
    public function save() {
        if ($this->id === NULL) {
            $this->add();
        }
        else {
            $this->update();
        }
    }
    public function add() {
        $stmt = $this->getPreparedStatement('addUser');
        $stmt->bindValue(':name', $this->name);
        $stmt->bindValue(':email', $this->email);
        $stmt->execute();
    }
    public function update() {
        $stmt = $this->getPreparedStatement('updateUser');
        $stmt->bindValue(':name', $this->name);
        $stmt->bindValue(':email', $this->email);
        $stmt->bindValue(':id', $this-id);
        $stmt->execute();
    }
}

Se si nota, i campi "nome" e "e-mail" si verificano ciascuno 7 volte in PHP e MySQL. Anche se questo non è un grosso problema con questo piccolo esempio, con tabelle grandi e un numero elevato di tabelle, questo è fuori controllo abbastanza rapidamente.

Come una breve nota a margine: con PHP in esecuzione come servizio Web, la durata della domanda è molto breve. Molte delle query che vengono eseguite, ad esempio l'aggiunta di un utente, vengono eseguite una sola volta durante la durata dell'applicazione, pertanto le istruzioni preparate non offrono un gran vantaggio. Anche con la condivisione delle connessioni, le singole istanze non hanno accesso all'istruzione precedentemente preparata (a meno che manchi qualcosa), quindi preparerebbe comunque l'istruzione.

Con alcune riflessioni a livello di database di base (i cui risultati sono memorizzati nella cache o generati automaticamente prima della distribuzione), è possibile creare istruzioni SQL automaticamente, eliminando la necessità di codificare le istruzioni di base SELECT / INSERT / UPDATE / DELETE singolarmente - riducendo notevolmente il codice.

-- (table create statement, of course, stays the same)

class User {
    protected $id;
    protected $name;
    protected $email;

    public function getById($id) {
        return MyDb::getById('Users', $id, $this);
    }
    public function save() {
        return MyDb::save('Users', $this);
    }
}

La mia domanda : è la duplicazione di codice che vale i pochi cicli della CPU e codice e ampli complessi; esigenze di manutenzione?

    
posta Doug Kress 03.09.2011 - 03:46
fonte

2 risposte

1

In sostanza ti stai chiedendo se la pulizia del codice sia più importante delle prestazioni; bene, questo può variare a seconda della situazione. Senza sapere veramente di più sulla situazione esatta, direi:

  • È improbabile che le prestazioni siano notevolmente peggiori con una soluzione ORM in questo caso. A meno che l'utilizzo della CPU non sia un collo di bottiglia noto sul server Web, è probabile che il codice spenda più tempo di attesa in attesa che il DB risponda di quanto non stia preparando l'istruzione SQL. Tuttavia, quando si tratta di domande sulle prestazioni, è una buona idea misurare (la risposta spesso non è quella che sembra la più ovvia).
  • Sono un convinto sostenitore delle soluzioni ORM. Hanno fatto molto per standardizzare come accedere al DB, consentire al resto del sistema di essere meno orientato al DB, togliere la possibilità di commettere semplici errori e mantenere le ripetizioni al minimo. Ci sono alcuni casi (complessi) in cui dovrete saltare attraverso i cerchi per far sì che l'ORM funzioni in modo accettabile, ma interrogare una singola tabella non lo è (e in questi casi, di solito potete codificare a mano qualunque cosa vi serva). Non conosco molte persone che l'hanno provato e sono tornate a non usarle.
risposta data 19.09.2011 - 13:45
fonte
1

My question: is the duplication of code worth the few CPU cycles and more complex code & maintenance needs?

No, non vale i cicli della CPU e il codice aggiuntivo. La maggior parte dei framework di accesso ai dati che conosco generano query se non ne fornite una personalizzata.

L'uso previsto rende il database il collo di bottiglia. Mantieni il tuo DAL generalizzato estendibile, in modo da poter sostituire il comportamento predefinito con qualcosa di personalizzato quando è necessario.

Even with connection sharing, the individual instances don't have access to the previously prepared statement (unless I'm missing something), so it would re-prepare the statement anyway.

Questo non è un problema qui. È il database che gestisce tali dichiarazioni. Il più delle volte vengono memorizzati nella cache su RDBMS, indipendentemente dal fatto che siano stati generati dinamicamente sul client o che la connessione sia stata chiusa. La generazione di query dinamiche e le istruzioni preparate non si escludono a vicenda, quindi ti incoraggio a utilizzarle, almeno per impedire le iniezioni SQL.

    
risposta data 19.09.2011 - 13:06
fonte

Leggi altre domande sui tag