Mysql
 sql >> Database >  >> RDS >> Mysql

Come gestisci le query SQL

La migliore linea d'azione per te dipenderà da come ti stai avvicinando all'accesso ai dati. Ci sono tre approcci che puoi adottare:

  • Utilizzare le procedure memorizzate
  • Mantieni le query nel codice (ma inserisci tutte le tue query in funzioni e correggi tutto per utilizzare PDO per i parametri, come accennato in precedenza)
  • Utilizza uno strumento ORM

Se si desidera passare il proprio SQL grezzo al motore di database, le procedure memorizzate sarebbero la strada da percorrere se tutto ciò che si desidera fare è estrarre l'SQL grezzo dal codice PHP ma mantenerlo relativamente invariato. Il dibattito tra stored procedure e raw SQL è un po' una guerra santa, ma K. Scott Allen fa un'osservazione eccellente, anche se usa e getta, in un articolo su versione dei database :

Tendo a propendere per non utilizzare le stored procedure. Ho lavorato su progetti in cui il DB ha un'API esposta tramite stored procedure, ma le stored procedure possono imporre alcune proprie limitazioni e quei progetti hanno tutti , a vari livelli, utilizzava SQL grezzo generato dinamicamente nel codice per accedere al DB.

Avere un livello API sul DB offre una migliore delineazione delle responsabilità tra il team DB e il team di sviluppo a scapito di parte della flessibilità che avresti se la query fosse mantenuta nel codice, tuttavia è meno probabile che i progetti PHP abbiano dimensioni considerevoli abbastanza squadre per beneficiare di questa definizione.

Concettualmente, dovresti probabilmente avere la versione del tuo database. In pratica, tuttavia, è molto più probabile che tu abbia solo la versione del codice rispetto a quella del database. È probabile che tu modifichi le tue query quando apporti modifiche al tuo codice, ma se stai modificando le query nelle procedure memorizzate memorizzate sul database, probabilmente non le controllerai quando esegui il check-in del codice e perdi molti dei vantaggi del controllo delle versioni per un'area significativa della tua applicazione.

Indipendentemente dal fatto che tu scelga o meno di non utilizzare le procedure memorizzate, dovresti almeno assicurarti che ogni operazione del database sia archiviata in una funzione indipendente anziché essere incorporata in ciascuno degli script della tua pagina, essenzialmente un livello API per il tuo DB che è mantenuto e versionato con il tuo codice. Se stai utilizzando stored procedure, ciò significherà effettivamente che hai due livelli API per il tuo DB, uno con il codice e uno con il DB, cosa che potresti ritenere complichi inutilmente le cose se il tuo progetto non ha team separati. Sicuramente sì.

Se il problema riguarda la precisione del codice, ci sono modi per rendere più presentabile il codice con SQL bloccato e la classe UserManager mostrata di seguito è un buon modo per iniziare:la classe contiene solo query relative alla tabella "utente", ogni query ha il proprio metodo nella classe e le query sono rientrate nelle istruzioni prepare e formattate come le formattereste in una procedura memorizzata.

// UserManager.php:

class UserManager
{
    function getUsers()
    {
        $pdo = new PDO(...);
        $stmt = $pdo->prepare('
            SELECT       u.userId as id,
                         u.userName,
                         g.groupId,
                         g.groupName
            FROM         user u
            INNER JOIN   group g
            ON           u.groupId = g.groupId
            ORDER BY     u.userName, g.groupName
        ');
        // iterate over result and prepare return value
    }

    function getUser($id) {
        // db code here
    }
}

// index.php:
require_once("UserManager.php");
$um = new UserManager;
$users = $um->getUsers();
foreach ($users as $user) echo $user['name'];

Tuttavia, se le tue query sono abbastanza simili ma hai un numero enorme di permutazioni nelle condizioni della tua query come paginazione complicata, ordinamento, filtraggio, ecc., uno strumento di mappatura oggetti/relazionale è probabilmente la strada da percorrere, sebbene il processo di revisione del codice esistente utilizzare lo strumento potrebbe essere piuttosto complicato.

Se decidi di indagare sugli strumenti ORM, dovresti guardare Propel , il componente ActiveRecord di Yii , o l'ORM PHP king-daddy, Dottrina . Ognuno di questi ti dà la possibilità di creare a livello di codice query sul tuo database con ogni sorta di logica complicata. Doctrine è la funzionalità più completa e ti consente di modellare il tuo database con elementi come il Set nidificato schema ad albero fuori dagli schemi.

In termini di prestazioni, le stored procedure sono le più veloci, ma generalmente non di molto rispetto a raw sql. Gli strumenti ORM possono avere un impatto significativo sulle prestazioni in diversi modi:query inefficienti o ridondanti, file IO di grandi dimensioni durante il caricamento delle librerie ORM su ogni richiesta, generazione SQL dinamica su ogni query... tutte queste cose possono avere un impatto, ma l'uso di uno strumento ORM può aumentare drasticamente la potenza a tua disposizione con una quantità di codice molto inferiore rispetto alla creazione del tuo livello DB con query manuali.

Gary Richardson è assolutamente corretto, tuttavia, se hai intenzione di continuare a utilizzare SQL nel tuo codice, dovresti sempre utilizzare le istruzioni preparate di PDO per gestire i parametri indipendentemente dal fatto che tu stia utilizzando una query o una stored procedure. La sanificazione dell'input viene eseguita per te da PDO.

// optional
$attrs = array(PDO::ATTR_PERSISTENT => true);

// create the PDO object
$pdo = new PDO("mysql:host=localhost;dbname=test", "user", "pass", $attrs);

// also optional, but it makes PDO raise exceptions instead of 
// PHP errors which are far more useful for debugging
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$stmt = $pdo->prepare('INSERT INTO venue(venueName, regionId) VALUES(:venueName, :regionId)');
$stmt->bindValue(":venueName", "test");
$stmt->bindValue(":regionId", 1);

$stmt->execute();

$lastInsertId = $pdo->lastInsertId();
var_dump($lastInsertId);

Avvertenza:supponendo che l'ID sia 1, lo script precedente genererà string(1) "1" . PDO->lastInsertId() restituisce l'ID come stringa indipendentemente dal fatto che la colonna effettiva sia un numero intero o meno. Questo probabilmente non sarà mai un problema per te poiché PHP esegue automaticamente il cast di stringhe in numeri interi.

Quanto segue produrrà bool(true) :

// regular equality test
var_dump($lastInsertId == 1); 

ma se hai un codice che si aspetta che il valore sia un intero, come is_int oppure "è davvero, veramente, uguale al 100%" operatore:

var_dump(is_int($lastInsertId));
var_dump($lastInsertId === 1);

potresti riscontrare dei problemi.

Modifica: Qualche buona discussione sulle procedure archiviate qui