web-dev-qa-db-fra.com

Confusion entre une requête préparée et une requête paramétrée en Python

Pour autant que je sache, les instructions préparées sont (principalement) une fonctionnalité de base de données qui vous permet de séparer les paramètres du code qui les utilise. Exemple:

PREPARE fooplan (int, text, bool, numeric) AS
    INSERT INTO foo VALUES($1, $2, $3, $4);
EXECUTE fooplan(1, 'Hunter Valley', 't', 200.00);

Une requête paramétrée substitue l’interpolation manuelle des chaînes, donc au lieu de faire

cursor.execute("SELECT FROM tablename WHERE fieldname = %s" % value)

nous pouvons faire

cursor.execute("SELECT FROM tablename WHERE fieldname = %s", [value])

Maintenant, il semble que les instructions préparées soient, pour la plupart, utilisées dans le langage de base de données et que les requêtes paramétrées soient principalement utilisées dans le langage de programmation se connectant à la base de données, bien que j'ai vu des exceptions à cette règle.

Le problème est que poser des questions sur la différence entre une instruction préparée et une requête paramétrée crée beaucoup de confusion. Leur objectif est certes le même, mais leur méthodologie semble distincte. Cependant, il existe sources indiquant que les deux sont identiques. MySQLdb et Psycopg2 semblent prendre en charge les requêtes paramétrées, mais pas les instructions préparées (par exemple, here pour MySQLdb et dans la liste TODO pour les pilotes postgres ou this answer dans le groupe sqlalchemy). En fait, il existe un Gist implémentant un curseur psycopg2 prenant en charge les instructions préparées et une explication minimale à ce sujet. Il existe également une suggestion de de sous-classer l'objet curseur dans psycopg2 pour fournir l'instruction préparée manuellement.

Je voudrais obtenir une réponse faisant autorité aux questions suivantes:

  • Existe-t-il une différence significative entre une instruction préparée et une requête paramétrée? Est-ce important dans la pratique? Si vous utilisez des requêtes paramétrées, avez-vous besoin de vous soucier des instructions préparées?

  • En cas de différence, quel est l'état actuel des instructions préparées dans l'écosystème Python? Quels adaptateurs de base de données prennent en charge les instructions préparées?

19
Robert Smith
  • Instruction préparée: référence à une routine d'interrogation pré-interprétée de la base de données, prête à accepter des paramètres

  • Requête paramétrée: Requête créée par votre code de telle sorte que vous transmettez des valeurs dans aux côtés de un SQL ayant des valeurs de substitution, généralement ? ou %s ou quelque chose de ce genre.

La confusion semble ici provenir de l’absence (apparente) de distinction entre la capacité d’obtenir directement un objet d’instruction préparé et la capacité de passer des valeurs dans une méthode de «requête paramétrée» qui fonctionne très bien comme un ... car c’est un , ou du moins en fait un pour vous.

Par exemple: l'interface C de la bibliothèque SQLite3 dispose de nombreux outils permettant de travailler avec les objets instruction préparés , mais le Python api ne les mentionne presque pas. Vous ne pouvez pas préparer une déclaration et l'utiliser plusieurs fois à tout moment. Au lieu de cela, vous pouvez utiliser sqlite3.executemany(sql, params) qui prend le code SQL, crée une instruction préparée en interne} _, puis utilise cette instruction dans une boucle pour traiter chacun de vos n-uplets de paramètres dans l'itérable que vous avez donné.

De nombreuses autres bibliothèques SQL dans Python se comportent de la même manière. Travailler avec des objets d'instructions préparés peut être très pénible et créer de l'ambiguïté. Dans un langage comme Python, qui privilégie la clarté et la facilité d'exécution de la vitesse d'exécution brute, ce n'est pas vraiment la meilleure option. Essentiellement, si vous devez effectuer des centaines de milliers, voire des millions, d'appels à une requête SQL complexe qui doit être réinterprétée à chaque fois, vous devriez probablement procéder différemment. Quoi qu'il en soit, les utilisateurs souhaitent parfois pouvoir accéder directement à ces objets, car si vous conservez la même instruction préparée autour du serveur de base de données, il ne sera plus nécessaire d'interpréter le même code SQL à plusieurs reprises. la plupart du temps, le problème sera abordé dans la mauvaise direction et vous obtiendrez des économies beaucoup plus importantes ailleurs ou en restructurant votre code. *

Plus important peut-être en général, c’est la façon dont les instructions préparées et les requêtes paramétrées préservent la santé de vos données et la séparent de votre code SQL. Ceci est largement préférable au formatage de chaîne! Vous devriez penser aux requêtes paramétrées et aux instructions préparées, sous une forme ou une autre, comme le seul moyen de transmettre des données variables de votre application à la base de données. Si vous essayez de construire l'instruction SQL autrement, elle ne fonctionnera pas seulement beaucoup plus lentement, mais vous serez vulnérable à autres problèmes .

* Par exemple, en produisant les données à alimenter dans la base de données dans une fonction de générateur, puis en utilisant executemany() pour les insérer toutes en même temps à partir du générateur, au lieu d'appeler execute() à chaque boucle.

tl; dr

Une requête paramétrée est une opération unique qui génère une instruction préparée en interne, puis transmet vos paramètres et s'exécute.

14
Mumbleskates

Premièrement, vos questions montrent une très bonne préparation - bien fait.

Je ne suis pas sûr, si je suis la personne à qui donner une réponse faisant autorité, mais je vais essayer d’expliquer ma compréhension de la situation.

Instruction préparée est un objet créé sur le serveur de base de données à la suite de l'instruction PREPARE, Transformant l'instruction SQL fournie en une sorte de procédure temporaire avec paramètres. L'instruction Préparée a la durée de vie de la session de base de données en cours et est rejetée une fois la session terminée. L'instruction SQL DEALOCATE permet de détruire explicitement l'instruction préparée.

Les clients de base de données peuvent utiliser l'instruction SQL EXECUTE pour exécuter l'instruction préparée en appelant son nom Et ses paramètres.

Instruction paramétrée est un alias pour une instruction préparée, comme d'habitude, l'instruction préparée a Certains paramètres.

Requête paramétrée semble être un alias utilisé moins souvent pour la même chose (24 mil hits Google pour Instruction paramétrée, 14 mil hits pour une requête paramétrée). Il est possible que certaines personnes utilisent Ce terme dans un autre but.

Les avantages des déclarations préparées sont les suivants:

  • exécution plus rapide de l'appel d'instructions préparé réel (sans compter le temps pour PREPARE)
  • résistance à l'attaque par injection SQL

Acteurs dans l'exécution d'une requête SQL

L'application réelle aura probablement les participants suivants:

  • code d'application
  • Package ORM (par exemple, sqlalchemy)
  • pilote de base de données
  • serveur de base de données

Du point de vue de l’application, il n’est pas facile de savoir si le code utilisera réellement une déclaration Préparée sur le serveur de base de données ou pas/ l’un des participants peut manquer de prise en charge des déclarations Préparées .

Conclusions

Dans le code de l'application empêche la mise en forme directe de la requête SQL, car celle-ci est sujette aux attaques par injection SQL. Pour cette raison, il est recommandé d'utiliser tout ce que l'ORM fournit à la requête paramétrée, même si cela n'entraîne pas l'utilisation d'instructions préparées côté serveur de base de données, car le code ORM peut être optimisé pour empêcher ce type d'attaque. .

Décidez si une déclaration préparée vaut pour des raisons de performance . Si vous avez une requête SQL simple, Qui n’est exécutée que quelques fois, cela n’aidera pas, mais cela ralentira parfois l’exécution d’un Bit.

Pour une requête complexe exécutée plusieurs fois et ayant un temps d'exécution relativement court, l'effet sera le plus important. Dans un tel cas, vous pouvez suivre ces étapes:

  • vérifiez que la base de données que vous allez utiliser prend en charge l'instruction PREPARE. Dans la plupart des cas, il sera présent.
  • vérifiez que le lecteur que vous utilisez prend en charge les instructions préparées et si ce n’est pas le cas, essayez d’en trouver un autre.
  • Vérifiez la prise en charge de cette fonctionnalité au niveau du package ORM. Parfois, il varie d’un pilote à l’autre (par exemple .____. Sqlalchemy énonce certaines limitations concernant les instructions préparées avec MySQL en raison de la façon dont MySQL gère Cela). 

Si vous êtes à la recherche d'une réponse faisant autorité, je me dirigerais vers les auteurs de sqlalchemy.

2
Jan Vlcinsky

Une instruction sql ne peut pas être exécutée immédiatement: le SGBD doit les interpréter avant l'exécution.

Les instructions préparées sont des instructions déjà interprétées, le SGBD modifie les paramètres et la requête démarre immédiatement. Ceci est une fonctionnalité de certains SGBD et vous pouvez obtenir une réponse rapide (comparable aux procédures stockées).

Les instructions paramétrées ne sont qu’un moyen de composer la chaîne de requête dans vos langages de programmation. Comme la manière dont la chaîne SQL est formée n'a pas d'importance, la réponse du SGBD est plus lente.

Si vous mesurez le temps en exécutant 3-4 fois la même requête (sélectionnez avec des conditions différentes), vous verrez le même temps avec des requêtes paramétrées, le temps est plus court à partir de la deuxième exécution de l'instruction préparée (la première fois que le SGBD doit interpréter le script en tous cas).

0
Fil