Mysql
 sql >> Base de données >  >> RDS >> Mysql

Comment gérez-vous les requêtes SQL

Le meilleur plan d'action pour vous dépendra de la façon dont vous abordez votre accès aux données. Vous pouvez adopter trois approches :

  • Utiliser des procédures stockées
  • Gardez les requêtes dans le code (mais placez toutes vos requêtes dans des fonctions et corrigez tout pour utiliser PDO pour les paramètres, comme mentionné précédemment)
  • Utiliser un outil ORM

Si vous souhaitez transmettre votre propre SQL brut au moteur de base de données, les procédures stockées seraient la solution si tout ce que vous voulez faire est d'extraire le SQL brut de votre code PHP tout en le gardant relativement inchangé. Le débat entre les procédures stockées et le SQL brut est un peu une guerre sainte, mais K. Scott Allen fait un excellent point - quoique jetable - dans un article sur bases de données de versioning :

J'ai tendance à ne pas utiliser de procédures stockées. J'ai travaillé sur des projets où la base de données a une API exposée via des procédures stockées, mais les procédures stockées peuvent imposer leurs propres limitations, et ces projets ont tous , à des degrés divers, ont utilisé du code SQL brut généré dynamiquement pour accéder à la base de données.

Avoir une couche API sur la base de données donne une meilleure délimitation des responsabilités entre l'équipe de base de données et l'équipe de développement au détriment d'une partie de la flexibilité que vous auriez si la requête était conservée dans le code, mais les projets PHP sont moins susceptibles d'avoir une taille importante suffisamment d'équipes pour bénéficier de cette délimitation.

Conceptuellement, vous devriez probablement faire versionner votre base de données. En pratique, cependant, vous êtes beaucoup plus susceptible de n'avoir que votre code versionné que d'avoir votre base de données versionnée. Vous modifierez probablement vos requêtes lorsque vous modifiez votre code, mais si vous modifiez les requêtes dans des procédures stockées stockées dans la base de données, vous ne les archiverez probablement pas lorsque vous archivez le code et vous perdez bon nombre des avantages de la gestion des versions pour une partie importante de votre application.

Que vous choisissiez ou non de ne pas utiliser de procédures stockées, vous devez au moins vous assurer que chaque opération de base de données est stockée dans une fonction indépendante plutôt que d'être intégrée dans chacun des scripts de votre page - essentiellement une couche API pour votre base de données qui est maintenu et versionné avec votre code. Si vous utilisez des procédures stockées, cela signifiera effectivement que vous avez deux couches d'API pour votre base de données, une avec le code et une avec la base de données, ce qui, selon vous, complique inutilement les choses si votre projet n'a pas d'équipes distinctes. Certainement.

Si le problème est lié à la propreté du code, il existe des moyens de rendre le code contenant du SQL plus présentable, et la classe UserManager illustrée ci-dessous est un bon moyen de commencer - la classe ne contient que des requêtes liées à la table 'user', chaque requête a sa propre méthode dans la classe et les requêtes sont mises en retrait dans les instructions de préparation et formatées comme vous le feriez dans une procédure stockée.

// 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'];

Cependant, si vos requêtes sont assez similaires mais que vous avez un grand nombre de permutations dans vos conditions de requête comme la pagination compliquée, le tri, le filtrage, etc., un outil de mappage objet/relationnel est probablement la voie à suivre, bien que le processus de refonte de votre code existant utiliser l'outil pourrait être assez compliqué.

Si vous décidez d'enquêter sur les outils ORM, vous devriez regarder Propel , le composant ActiveRecord de Yii , ou l'ORM PHP king-daddy, Doctrine . Chacun d'entre eux vous donne la possibilité de créer par programmation des requêtes dans votre base de données avec toutes sortes de logiques compliquées. Doctrine est le plus complet, vous permettant de modéliser votre base de données avec des choses comme le Ensemble imbriqué motif d'arbre prêt à l'emploi.

En termes de performances, les procédures stockées sont les plus rapides, mais généralement pas beaucoup plus que SQL brut. Les outils ORM peuvent avoir un impact significatif sur les performances de plusieurs manières :requêtes inefficaces ou redondantes, énormes E/S de fichiers lors du chargement des bibliothèques ORM à chaque requête, génération SQL dynamique sur chaque requête... toutes ces choses peuvent avoir un impact, mais l'utilisation d'un outil ORM peut augmenter considérablement la puissance dont vous disposez avec une quantité de code beaucoup plus petite que la création de votre propre couche DB avec des requêtes manuelles.

Gary Richardson a tout à fait raison, si vous continuez à utiliser SQL dans votre code, vous devez toujours utiliser les instructions préparées de PDO pour gérer les paramètres, que vous utilisiez une requête ou une procédure stockée. La désinfection des entrées est effectuée pour vous par 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);

Mise en garde :en supposant que l'ID est 1, le script ci-dessus affichera string(1) "1" . PDO->lastInsertId() renvoie l'ID sous forme de chaîne, que la colonne réelle soit un entier ou non. Cela ne vous posera probablement jamais de problème, car PHP effectue automatiquement la conversion des chaînes en entiers.

Ce qui suit affichera bool(true) :

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

mais si vous avez du code qui attend que la valeur soit un entier, comme is_int ou "est vraiment, vraiment, 100 % égal à" opérateur :

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

vous pourriez rencontrer des problèmes.

Modifier : Une bonne discussion sur les procédures stockées ici