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

Comparaison de SQL, de générateurs de requêtes et d'ORM


Introduction

L'utilisation d'une base de données pour gérer les données de votre application est l'un des choix les plus courants pour la persistance des données. Les bases de données permettent un stockage et une récupération rapides des informations, fournissent des garanties d'intégrité des données et offrent une persistance au-delà de la durée de vie d'une instance d'application individuelle. Il existe d'innombrables types de bases de données disponibles pour répondre aux exigences de votre projet et à vos préférences.

Cependant, travailler directement avec les bases de données de votre application n'est pas toujours facile. Les différences dans la manière dont les structures de données sont représentées entraînent souvent des difficultés. La difficulté à exprimer des subtilités sur les relations entre différentes entités peut également causer des problèmes. Pour résoudre ce problème, de nombreux outils différents ont été créés pour servir d'interface entre l'application principale et la couche de données.

Dans ce guide, nous examinerons certaines des différences qui surviennent entre trois approches courantes :le SQL brut, les générateurs de requêtes et les ORM (mappeurs relationnels objet). Nous comparerons certains des avantages et des inconvénients de chaque approche, puis terminerons par un glossaire des termes couramment utilisés pour vous aider à vous familiariser avec certains concepts clés.

En guise de résumé simplifié, voici une vue d'ensemble des forces et faiblesses de chaque approche :

Approche Base de données / Programmation axée Gestion pratique Niveau d'abstraction Niveau de complexité
SQL brut orienté base de données élevé aucun faible
Constructeurs de requêtes mixte faible faible faible
ORM orienté programmation faible élevé élevé


Gestion des données avec du SQL brut ou un autre langage d'interrogation natif de la base de données

Certaines applications s'interfacent directement avec la base de données en écrivant et en exécutant des requêtes à l'aide du langage natif pris en charge par le moteur de base de données. Souvent, un pilote de base de données suffit pour se connecter, s'authentifier et communiquer avec l'instance de base de données.

Les développeurs peuvent envoyer des requêtes écrites dans la langue maternelle de la base de données via la connexion. En retour, la base de données fournira les résultats de la requête, également dans l'un de ses formats natifs. Pour de nombreuses bases de données relationnelles, le langage d'interrogation de choix est SQL.

La plupart des bases de données relationnelles, ainsi que certaines bases de données non relationnelles, prennent en charge le langage de requête structuré, également appelé SQL, pour créer et exécuter des requêtes puissantes. SQL est utilisé pour gérer les données depuis les années 1970, il est donc bien pris en charge et standardisé dans une certaine mesure.


Avantages des requêtes natives

L'utilisation de SQL ou d'un autre langage natif de base de données présente des avantages évidents.

L'un des avantages est que les développeurs écrivent et gèrent les requêtes de base de données et gèrent les résultats de manière explicite. Bien que cela puisse représenter beaucoup de travail supplémentaire, cela signifie qu'il y a peu de surprises quant à ce que la base de données stocke, comment elle représente vos données et comment elle fournira ces données lorsqu'elles seront récupérées ultérieurement. Le manque d'abstraction signifie qu'il y a moins de "pièces mobiles" qui peuvent conduire à l'incertitude.

Les performances en sont un exemple. Alors que des couches d'abstraction sophistiquées génèrent des requêtes SQL en traduisant des instructions de programmation, le SQL généré peut être très inefficace. Des clauses inutiles, des requêtes trop larges et d'autres incidents peuvent entraîner des opérations de base de données lentes qui peuvent être fragiles et difficiles à déboguer. En écrivant nativement en SQL, vous pouvez utiliser toutes vos connaissances du domaine et votre bon sens pour éviter de nombreuses catégories de problèmes d'interrogation

Une autre raison d'utiliser l'interrogation native de la base de données est la flexibilité. Aucune abstraction n'est susceptible d'être aussi flexible que le langage d'interrogation de base de données natif. Des niveaux d'abstraction plus élevés tentent de combler le fossé entre deux paradigmes différents, ce qui peut restreindre les types d'opérations qu'ils peuvent exprimer. Toutefois, lorsque vous écrivez en SQL brut, vous pouvez tirer parti de toutes les fonctionnalités de votre moteur de base de données et exprimer des requêtes plus complexes.



Inconvénients des requêtes natives

Bien que l'interrogation native ait des points forts certains, elle n'est pas sans problèmes.

Lorsque vous interagissez avec une base de données à partir d'une application utilisant du SQL brut, vous devez comprendre la structure de données sous-jacente afin de composer des requêtes valides. Vous êtes entièrement responsable de la traduction entre les types de données et les structures que votre application utilise et les constructions disponibles dans le système de base de données.

Une autre chose à garder à l'esprit lorsque vous travaillez avec du SQL brut est qu'il vous appartient entièrement de gérer la sécurité de votre entrée. Cela est particulièrement vrai si vous stockez des données fournies par des utilisateurs externes, où une entrée spécialement conçue pourrait amener votre base de données à exposer des informations que vous n'aviez pas l'intention d'autoriser.

Ce type d'exploit est appelé injection SQL et constitue un problème potentiel chaque fois que l'entrée de l'utilisateur peut affecter l'état de la base de données. Les outils d'abstraction supérieurs nettoient souvent automatiquement les entrées de l'utilisateur, ce qui vous aide à éviter ce type de problèmes.

Travailler avec des langages de requête natifs signifie presque toujours composer des requêtes avec des chaînes régulières. Cela peut être un processus pénible dans les cas où vous devez échapper une entrée et concaténer des chaînes pour créer une requête valide. Vos opérations de base de données peuvent être enveloppées dans de nombreuses couches de manipulation de chaînes qui ont un fort potentiel de mutilation accidentelle des données.



Résumé des requêtes natives

Bien que nous ayons principalement parlé de SQL dans cette section, la plupart des informations ici s'appliquent également à n'importe quel langage d'interrogation de base de données natif. Pour résumer, le SQL brut ou l'utilisation directe de tout langage d'interrogation équivalent vous rapproche le plus des abstractions utilisées par la base de données pour stocker et gérer les données, mais vous oblige à faire tout le gros du travail de gestion manuelle de vos données.




Gestion des données avec les générateurs de requêtes

Une approche alternative à l'utilisation de langages d'interrogation natifs de base de données tels que SQL consiste à utiliser un outil ou une bibliothèque appelé générateur de requêtes pour communiquer avec votre base de données.


Que sont les générateurs de requêtes SQL ?

Un générateur de requêtes SQL ajoute une couche d'abstraction au-dessus des langages d'interrogation natifs des bases de données brutes. Pour ce faire, ils formalisent les modèles de requête et fournissent des méthodes ou des fonctions qui ajoutent un assainissement des entrées et échappent automatiquement les éléments pour une intégration plus facile dans les applications.

Les structures et les actions prises en charge par la couche de base de données sont encore assez reconnaissables lors de l'utilisation des générateurs de requêtes SQL. Cela vous permet de travailler avec des données par programmation tout en restant relativement proche des données.

Généralement, les générateurs de requêtes fournissent une interface qui utilise des méthodes ou des fonctions pour ajouter une condition à une requête. En enchaînant les méthodes, les développeurs peuvent composer des requêtes complètes de base de données à partir de ces "clauses" individuelles.



Avantages des constructeurs de requêtes SQL

Étant donné que les générateurs de requêtes utilisent les mêmes constructions (méthodes ou fonctions) que le reste de votre application, les développeurs les trouvent souvent plus faciles à gérer à long terme que les requêtes de base de données brutes écrites sous forme de chaînes. Il est simple de faire la différence entre les opérateurs et les données et il est facile de décomposer les requêtes en blocs logiques qui gèrent des parties spécifiques d'une requête.

Pour certains développeurs, un autre avantage de l'utilisation d'un générateur de requêtes SQL est qu'il ne masque pas toujours le langage de requête sous-jacent. Bien que les opérations puissent utiliser des méthodes au lieu de chaînes, elles peuvent être assez transparentes, ce qui permet aux personnes familiarisées avec la base de données de comprendre plus facilement ce qu'une opération va faire. Ce n'est pas toujours le cas lorsque vous utilisez des niveaux d'abstraction plus élevés.

Les constructeurs de requêtes SQL prennent souvent également en charge plusieurs backends de données, en faisant abstraction de certaines des différences subtiles dans diverses bases de données relationnelles, par exemple. Cela vous permet d'utiliser les mêmes outils pour des projets utilisant des bases de données différentes. Cela peut même faciliter légèrement la migration vers une nouvelle base de données.



Inconvénients des constructeurs de requêtes SQL

Les générateurs de requêtes SQL souffrent de quelques-uns des mêmes inconvénients que les langages de requête natifs.

Une critique populaire est que les générateurs de requêtes SQL exigent toujours que vous compreniez et teniez compte des structures et des capacités de la base de données. Ce n'est pas une abstraction assez utile pour certains développeurs. Cela signifie que vous devez avoir une assez bonne compréhension de SQL en plus de la syntaxe et des capacités spécifiques du générateur de requête lui-même.

De plus, les générateurs de requêtes SQL exigent toujours que vous définissiez la relation entre les données que vous récupérez et les données de votre application. Il n'y a pas de synchronisation automatique entre vos objets en mémoire et ceux de la base de données.

Bien que les générateurs de requêtes émulent souvent le langage d'interrogation avec lequel ils sont conçus pour fonctionner, la couche d'abstraction supplémentaire peut signifier que certaines opérations ne sont parfois pas possibles avec les méthodes fournies. Habituellement, il existe un mode "brut" pour envoyer des requêtes directement au backend, en contournant l'interface typique du générateur de requêtes, mais cela évite le problème plutôt que de le résoudre.



Résumé des constructeurs de requêtes SQL

Dans l'ensemble, les générateurs de requêtes SQL offrent une fine couche d'abstraction qui cible spécifiquement certains des principaux problèmes liés au travail direct avec des langages natifs de base de données. Les générateurs de requêtes SQL fonctionnent presque comme un système de modèles pour les requêtes, permettant aux développeurs de faire la distinction entre le travail direct avec la base de données et l'ajout de couches d'abstraction supplémentaires.




Gérer les données avec les ORM

Un pas plus haut dans la hiérarchie d'abstraction se trouvent les ORM. Les ORM visent généralement une abstraction plus complète dans l'espoir d'une intégration plus fluide avec les données de l'application.


Que sont les ORM ?

Les mappeurs relationnels objet, ou ORM, sont des logiciels dédiés à la traduction entre les représentations de données dans les bases de données relationnelles et la représentation en mémoire utilisée avec la programmation orientée objet (POO). L'ORM fournit une interface orientée objet vers les données de la base de données, en essayant d'utiliser des concepts de programmation familiers et de réduire la quantité de code passe-partout nécessaire pour accélérer le développement.

En général, les ORM servent de couche d'abstraction destinée à aider les développeurs à travailler avec des bases de données sans changer radicalement le paradigme orienté objet. Cela peut être utile en réduisant la charge mentale d'adaptation aux spécificités du format de stockage d'une base de données.

En particulier, les objets de la programmation orientée objet ont tendance à encoder beaucoup d'états en leur sein et peuvent avoir des relations complexes avec d'autres objets via l'héritage et d'autres concepts POO. Mapper ces informations de manière fiable dans un paradigme relationnel orienté table n'est souvent pas simple et peut nécessiter une bonne compréhension des deux systèmes. Les ORM tentent d'alléger ce fardeau en automatisant une partie de ce mappage et en fournissant des interfaces expressives vers les données au sein du système.



Les enjeux des ORM sont-ils spécifiques à la programmation orientée objet et les bases de données relationnelles ?

Par définition, les ORM sont spécifiquement conçus pour faire l'interface entre les langages d'application orientés objet et les bases de données relationnelles. Cependant, essayer de mapper et de traduire entre les abstractions de structure de données utilisées dans les langages de programmation et celles utilisées par les magasins de bases de données est un problème plus général qui peut exister lorsque les abstractions ne s'alignent pas proprement.

Selon le paradigme de programmation (orienté objet, fonctionnel, procédural, etc.) et le type de base de données (relationnelle, document, clé-valeur, etc.), différentes quantités d'abstraction peuvent être utiles. Souvent, la complexité des structures de données au sein de l'application détermine la facilité d'interface avec le magasin de données.

La programmation orientée objet a tendance à produire de nombreuses structures avec un état et des relations significatifs qui doivent être pris en compte. Certains autres paradigmes de programmation sont plus explicites quant à l'endroit où l'état est stocké et comment il est géré. Par exemple, les langages purement fonctionnels n'autorisent pas l'état mutable, donc l'état est souvent une entrée pour les fonctions ou les objets qui génèrent un nouvel état. Cette séparation nette des données des actions, ainsi que l'explicité des cycles de vie des états peuvent aider à simplifier l'interaction avec la base de données.

Quoi qu'il en soit, l'option d'interface avec une base de données via un logiciel qui cartographie entre deux représentations différentes est souvent disponible. Ainsi, alors que les ORM décrivent un sous-ensemble spécifique de ceux-ci avec des défis uniques, le mappage entre la mémoire de l'application et le stockage persistant nécessite souvent une attention indépendante des détails.



Enregistrement actif vs ORM de mappage de données

Différents ORM utilisent différentes stratégies pour mapper les structures d'application et de base de données. Les deux principales catégories sont le modèle d'enregistrement actif et le modèle de mappeur de données .

Le modèle d'enregistrement actif tente d'encapsuler les données de la base de données dans la structure des objets de votre code. Les objets contiennent des méthodes pour enregistrer, mettre à jour ou supprimer de la base de données et les modifications apportées à vos objets sont censées être facilement répercutées dans la base de données. En général, un objet d'enregistrement actif dans votre application représente un enregistrement dans une base de données.

Les implémentations d'enregistrements actifs vous permettent de gérer votre base de données en créant et en connectant des classes et des instances dans votre code. Étant donné que ces instances de classe mappent généralement directement aux enregistrements de la base de données, il est facile de conceptualiser le contenu de votre base de données si vous comprenez quels objets sont utilisés dans votre code.

Malheureusement, cela peut aussi présenter des inconvénients majeurs. Les applications ont tendance à être étroitement liées à la base de données, ce qui peut entraîner des problèmes lors de la migration vers une nouvelle base de données ou même lors du test de votre code. Votre code a tendance à s'appuyer sur la base de données pour combler les lacunes qui ont été déchargées de vos objets. La traduction « magique » entre ces deux domaines peut également entraîner des problèmes de performances, car le système tente de mapper de manière transparente des objets complexes à la structure de données sous-jacente.

Le modèle de mappeur de données est l'autre modèle ORM commun. Comme le modèle d'enregistrement actif, le mappeur de données tente d'agir comme une couche indépendante entre votre code et votre base de données qui sert d'intermédiaire entre les deux. Cependant, au lieu d'essayer d'intégrer de manière transparente des objets et des enregistrements de base de données, il se concentre sur la tentative de découpler et de traduire entre eux tout en laissant chacun exister indépendamment. Cela peut aider à séparer votre logique métier des détails liés à la base de données qui traitent des mappages, de la représentation, de la sérialisation, etc.

Ainsi, plutôt que de laisser le système ORM déterminer comment mapper les objets et les tables de la base de données, le développeur est responsable du mappage explicite entre les deux. Cela peut aider à éviter un couplage étroit et des opérations en coulisses au détriment d'un travail beaucoup plus important pour déterminer les mappages appropriés.



Avantages des ORM

Les ORM sont populaires pour de nombreuses raisons.

Ils aident à résumer le domaine de données sous-jacent en quelque chose sur lequel il est facile de raisonner dans le contexte de votre application. Plutôt que de considérer le stockage de données comme un système indépendant, les ORM vous aident à accéder aux systèmes de données et à les gérer comme une extension de votre travail actuel. Cela peut aider les développeurs à travailler plus rapidement sur la logique métier de base au lieu de s'enliser dans les nuances de leurs backends de stockage.

Un autre effet secondaire de cela est que les ORM suppriment une grande partie du passe-partout nécessaire à l'interface avec les bases de données. Les ORM sont souvent accompagnés d'outils de migration qui vous aident à gérer les modifications du schéma de base de données en fonction des modifications apportées à votre code. Vous n'avez pas nécessairement besoin de déterminer le schéma de base de données parfait à l'avance si votre ORM peut vous aider à gérer les modifications apportées à la structure de la base de données. Les modifications apportées à votre application et à votre base de données sont souvent identiques ou étroitement liées, ce qui permet de suivre les modifications apportées à votre base de données lorsque vous modifiez votre code.



Inconvénients des ORM

Les ORM ne sont pas sans défauts. Dans de nombreux cas, ceux-ci découlent des mêmes décisions qui rendent les ORM utiles.

L'un des problèmes fondamentaux des ORM est la tentative de masquer les détails du backend de la base de données. Cet obscurcissement facilite le travail avec les ORM dans des cas simples ou sur de petites échelles de temps, mais entraîne souvent des problèmes à mesure que la complexité augmente.

L'abstraction n'est jamais complète à 100 % et tenter d'utiliser un ORM sans comprendre le langage d'interrogation sous-jacent ou la structure de la base de données conduit souvent à des hypothèses problématiques. Cela peut rendre le débogage et le réglage des performances difficiles, voire impossibles.

Le problème le plus connu du travail avec les ORM est peut-être l'inadéquation de l'impédance relationnelle objet, un terme utilisé pour décrire la difficulté de traduction entre la programmation orientée objet et le paradigme relationnel utilisé par les bases de données relationnelles. Les incompatibilités entre les modèles de données utilisés par ces deux catégories de technologie signifient qu'une abstraction supplémentaire imparfaite est nécessaire à chaque augmentation de la complexité. L'incompatibilité d'impédance relationnelle objet a été appelée le Vietnam de l'informatique (en référence à la guerre du Vietnam) en raison de sa tendance à augmenter la complexité au fil du temps et à conduire à des situations où les chemins vers le succès ou le changement de cap sont difficiles ou impossibles.

En général, les ORM ont tendance à être plus lents que les alternatives, en particulier avec des requêtes complexes. Les ORM génèrent souvent des requêtes compliquées pour des opérations de base de données relativement simples, car ils utilisent des modèles généraux qui doivent être suffisamment flexibles pour gérer d'autres cas. Le fait de se fier à l'ORM pour faire ce qu'il faut en toutes circonstances peut entraîner des erreurs coûteuses qui peuvent être difficiles à rattraper dès le départ.



Résumé des ORM

Les ORM peuvent être des abstractions utiles qui facilitent grandement le travail avec les bases de données. Ils peuvent vous aider à concevoir et à itérer rapidement et à combler les différences conceptuelles entre la logique d'application et les structures de base de données. Cependant, bon nombre de ces avantages agissent comme une épée à double tranchant. Ils peuvent vous empêcher de comprendre vos bases de données et compliquer le débogage, le changement de paradigme ou l'amélioration des performances.




Glossaire

Lorsque vous travaillez avec des technologies qui s'interfacent entre les bases de données et les applications, vous pouvez rencontrer une terminologie qui ne vous est pas familière. Dans cette section, nous passerons brièvement en revue certains des termes les plus courants que vous pourriez rencontrer, dont certains ont été couverts plus tôt dans cet article et d'autres non.

  • Mappeur de données : Un mappeur de données est un modèle de conception ou un logiciel qui mappe les structures de données de programmation à celles stockées dans une base de données. Les mappeurs de données tentent de synchroniser les modifications entre les deux sources tout en les gardant indépendantes l'une de l'autre. Le mappeur lui-même est responsable du maintien d'une traduction fonctionnelle, permettant aux développeurs d'itérer les structures de données de l'application sans se soucier de la représentation de la base de données.
  • Pilote de base de données : Un pilote de base de données est un logiciel conçu pour encapsuler et activer les connexions entre une application et une base de données. Les pilotes de base de données résument les détails de bas niveau sur la façon d'établir et de gérer les connexions et fournissent une interface de programmation unifiée au système de base de données. En règle générale, les pilotes de base de données constituent le niveau d'abstraction le plus bas que les développeurs utilisent pour interagir avec les bases de données, les outils de niveau supérieur s'appuyant sur les fonctionnalités fournies par le pilote.
  • Attaque par injection : Une attaque par injection est une attaque dans laquelle un utilisateur malveillant tente d'exécuter des opérations de base de données indésirables à l'aide d'entrées spécialement conçues dans des champs d'application accessibles à l'utilisateur. Souvent, cela est utilisé pour récupérer des données qui ne devraient pas être accessibles ou pour supprimer ou modifier des informations dans la base de données.
  • ORM : Les ORM, ou mappeurs relationnels objet, sont des couches d'abstraction qui traduisent entre les représentations de données utilisées dans les bases de données relationnelles et la représentation en mémoire utilisée avec la programmation orientée objet. L'ORM fournit une interface orientée objet vers les données de la base de données, en essayant de réduire la quantité de code et d'utiliser des archétypes familiers pour accélérer le développement.
  • Non-concordance d'impédance relationnelle objet : L'inadéquation d'impédance relationnelle objet fait référence à la difficulté de traduction entre une application orientée objet et une base de données relationnelle. Étant donné que les structures de données varient considérablement, il peut être difficile de muter et de transcrire de manière fidèle et performante les structures de données programmatiques au format utilisé par le backend de stockage.
  • Cadre de persistance : Un framework de persistance est une couche d'abstraction middleware développée pour combler le fossé entre les données du programme et les bases de données. Les frameworks de persistance peuvent également être des ORM si l'abstraction qu'ils utilisent mappe des objets sur des entités relationnelles.
  • Créateur de requête : Un générateur de requêtes est une couche d'abstraction qui aide les développeurs à accéder aux bases de données et à les contrôler en fournissant une interface contrôlée qui ajoute des fonctionnalités de convivialité, de sécurité ou de flexibilité. En règle générale, les générateurs de requêtes sont relativement légers, se concentrent sur la facilitation de l'accès aux données et de la représentation des données, et n'essaient pas de traduire les données dans un paradigme de programmation spécifique.
  • SQL : SQL, ou langage de requête structuré, est un langage spécifique à un domaine développé pour gérer des systèmes de gestion de bases de données relationnelles. Il peut être utilisé pour interroger, définir et manipuler des données dans une base de données ainsi que leurs structures organisationnelles. SQL est omniprésent parmi les bases de données relationnelles.


Conclusion

Dans cet article, nous avons examiné quelques options différentes pour s'interfacer avec votre base de données à partir de votre application. Nous avons examiné les différents niveaux d'abstraction et la flexibilité offerte par l'utilisation de langages d'interrogation natifs de base de données tels que SQL, en utilisant un générateur de requêtes pour créer des requêtes en toute sécurité et des ORM pour fournir un niveau d'abstraction plus complet.

Chacune de ces approches a ses utilisations et certaines peuvent être mieux adaptées à certains types d'applications que d'autres. Il est important de comprendre les exigences de votre application, la connaissance de la base de données de votre organisation et les coûts des abstractions (ou de leur absence) que vous choisissez de mettre en œuvre. Dans l'ensemble, la compréhension de chaque approche vous donnera les meilleures chances de sélectionner l'option qui conviendra le mieux à vos projets.