it-swarm.com.de

Verwirrung zwischen vorbereiteter Anweisung und parametrisierter Abfrage in Python

Soweit ich verstanden habe, sind vorbereitete Anweisungen (hauptsächlich) eine Datenbankfunktion, mit der Sie Parameter von dem Code trennen können, der solche Parameter verwendet. Beispiel:

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

Eine parametrisierte Abfrage ersetzt die manuelle Zeichenketteninterpolation, anstatt dies zu tun

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

wir können tun

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

Es scheint nun so, als würden vorbereitete Anweisungen zum größten Teil in der Datenbanksprache verwendet und parametrisierte Abfragen hauptsächlich in der Programmiersprache verwendet, die eine Verbindung zur Datenbank herstellt, obwohl ich Ausnahmen von dieser Regel gesehen habe.

Das Problem ist, dass die Frage nach dem Unterschied zwischen der vorbereiteten Anweisung und der parametrisierten Abfrage viel Verwirrung stiftet. Ihr Zweck ist zwar derselbe, aber ihre Methodik scheint verschieden zu sein. Es gibt jedoch sources , die darauf hinweisen, dass beide gleich sind. MySQLdb und Psycopg2 unterstützen scheinbar parametrisierte Abfragen, unterstützen jedoch keine vorbereiteten Anweisungen (z. B. hier für MySQLdb und in der TODO-Liste für Postgres-Treiber oder diese Antwort in der sqlalchemy-Gruppe). Tatsächlich gibt es einen Gist , der einen psycopg2-Cursor implementiert, der die vorbereiteten Anweisungen und eine minimale erklärung darüber unterstützt. Es gibt auch einen Vorschlag der Unterklasse des Cursorobjekts in psycopg2, um die vorbereitete Anweisung manuell bereitzustellen.

Ich hätte gerne eine verbindliche Antwort auf folgende Fragen:

  • Gibt es einen bedeutsamen Unterschied zwischen der vorbereiteten Anweisung und der parametrisierten Abfrage? Ist das in der Praxis wichtig? Wenn Sie parametrisierte Abfragen verwenden, müssen Sie sich um vorbereitete Anweisungen sorgen?

  • Wenn es einen Unterschied gibt, wie ist der aktuelle Status der vorbereiteten Anweisungen im Python-Ökosystem? Welche Datenbankadapter unterstützen vorbereitete Anweisungen?

19
Robert Smith
  • Prepared-Anweisung: Ein Verweis auf eine vordefinierte Abfrageroutine in der Datenbank, die bereit ist, Parameter zu akzeptieren

  • Parametrisierte Abfrage: Eine Abfrage, die von Ihrem Code so erstellt wird, dass Sie Werte in nebeneinander einiger SQL-Werte übergeben, die Platzhalterwerte enthalten, normalerweise ? oder %s oder etwas davon.

Die Verwirrung scheint hier auf den (scheinbaren) Mangel an Unterscheidung zwischen der Fähigkeit, ein vorbereitete Anweisungsobjekt direkt abzurufen, und der Fähigkeit, Werte in eine 'parametrisierte Abfrage' -Methode zu übergeben, die sehr wie eine… oder macht wenigstens eins für dich.

Zum Beispiel: Die C-Schnittstelle der SQLite3-Bibliothek verfügt über viele Werkzeuge zum Arbeiten mit präparierten Anweisungsobjekten , aber die Python-API erwähnt diese kaum. Sie können eine Anweisung nicht vorbereiten und sie mehrmals verwenden, wann immer Sie möchten. Stattdessen können Sie sqlite3.executemany(sql, params) verwenden, das den SQL-Code verwendet, eine vorbereitete Anweisung intern erstellt und diese Anweisung dann in einer Schleife verwendet, um jedes Ihrer Parametertupel in der von Ihnen angegebenen Iterierfunktion zu verarbeiten.

Viele andere SQL-Bibliotheken in Python verhalten sich genauso. Das Arbeiten mit vorbereiteten Anweisungsobjekten kann sehr schmerzhaft sein und zu Mehrdeutigkeiten führen. In einer Sprache wie Python, die eine klare Neigung zu Klarheit und Nachgiebigkeit über die reine Ausführungsgeschwindigkeit hat, sind sie nicht wirklich die beste Option. Wenn Sie feststellen müssen, dass Sie Hunderttausende oder Millionen von Aufrufen einer komplexen SQL-Abfrage durchführen müssen, die jedes Mal neu interpretiert wird, sollten Sie die Dinge wahrscheinlich anders machen. Unabhängig davon wünschen die Leute manchmal, sie hätten direkten Zugriff auf diese Objekte, da derselbe SQL-Code nicht immer und immer wieder von demselben Datenbankserver interpretiert werden muss, wenn Sie dieselbe vorbereitete Anweisung beibehalten. Meistens wird das Problem aus der falschen Richtung angegangen, und Sie werden an anderer Stelle viel größere Einsparungen erzielen oder Ihren Code umstrukturieren. *

Vielleicht wichtiger ist im Allgemeinen die Art und Weise, wie vorbereitete Anweisungen und parametrisierte Abfragen Ihre Daten hygienisch und vom SQL-Code getrennt halten. Dies ist der Formatierung von Strings weit vorzuziehen! Sie sollten sich parametrisierte Abfragen und vorbereitete Anweisungen in der einen oder anderen Form als vorstellen, um Variablendaten aus Ihrer Anwendung in die Datenbank zu übergeben. Wenn Sie versuchen, die SQL-Anweisung anderweitig zu erstellen, wird sie nicht nur erheblich langsamer ausgeführt, sondern Sie sind anfällig für andere Probleme .

* z. B. durch Erzeugen der Daten, die in die DB in einer Generatorfunktion eingespeist werden sollen, und dann mit executemany() alle auf einmal vom Generator eingefügt, anstatt execute() bei jeder Schleife aufzurufen.

tl; dr

Eine parametrisierte Abfrage ist eine einzelne Operation, die intern eine vorbereitete Anweisung generiert, dann Ihre Parameter übergibt und ausführt.

14
Mumbleskates

Erstens zeigen Ihre Fragen eine sehr gute Vorbereitung - gut gemacht.

Ich bin mir nicht sicher, ob ich die Person bin, die eine maßgebliche Antwort gibt, aber ich werde versuchen, mein Verständnis der Situation zu erklären.

Prepared-Anweisung ist ein Objekt, das auf der Seite des Datenbankservers als Ergebnis der Anweisung PREPARE Erstellt wurde. Die angegebene SQL-Anweisung wird in eine Art temporäre Prozedur mit Parametern umgewandelt. Die vorbereitete -Anweisung hat eine Gültigkeitsdauer der aktuellen Datenbanksitzung und wird verworfen, nachdem die Sitzung beendet ist. Die SQL-Anweisung DEALOCATE ermöglicht das explizite Löschen der vorbereiteten Anweisung.

Datenbankclients können die SQL-Anweisung EXECUTE verwenden, um die vorbereitete Anweisung auszuführen, indem ihr Name und ihre Parameter aufgerufen werden.

Parametrized-Anweisung ist ein Alias ​​für vorbereitete Anweisung. Normalerweise hat die vorbereitete Anweisung einige Parameter.

Parametrized query scheint ein weniger häufig verwendeter Alias ​​für dasselbe zu sein (24-Millionen-Google-Treffer für die Parametrisierte Anweisung, 14-Mil-Treffer für die parametrisierte Abfrage). Es ist möglich, dass einige Leute diesen Begriff für einen anderen Zweck verwenden.

Vorteile von vorbereiteten Anweisungen sind:

  • schnellere Ausführung des Aufrufs der vorbereiteten Anweisungen (die Zeit für PREPARE wird nicht berücksichtigt)
  • beständigkeit gegen SQL-Injection-Angriff

Spieler bei der Ausführung einer SQL-Abfrage

Eine echte Anwendung wird wahrscheinlich folgende Teilnehmer haben:

  • anwendungscode
  • ORM-Paket (z. B. SQL-Chemie)
  • datenbanktreiber
  • datenbankserver

Aus der Sicht der Anwendung ist es nicht leicht zu wissen, ob der Code die vorbereitete -Anweisung auf dem Datenbankserver tatsächlich verwendet oder nicht, da einem der Teilnehmer möglicherweise keine vorbereiteten -Anweisungen zur Verfügung stehen.

Schlussfolgerungen

In Anwendungscode verhindert die direkte Formung von SQL-Abfragen, da diese zu SQL-Injection-Angriffen neigen. Aus diesem Grund wird empfohlen, das zu verwenden, was ORM für die parametrisierte Abfrage bereitstellt, auch wenn dies nicht mit der Verwendung vorbereiteter Anweisungen auf Datenbankserverseite zusammenhängt, da der ORM-Code optimiert werden kann, um diese Art von Angriff zu verhindern .

Entscheide, ob sich eine vorbereitete Aussage aus Leistungsgründen lohnt. Wenn Sie eine einfache SQL-Abfrage haben, die nur wenige Male ausgeführt wird, wird dies nicht helfen. Manchmal verlangsamt es sogar die Ausführung eines Bits

Bei komplexen Abfragen, die viele Male ausgeführt werden und relativ kurze Ausführungszeiten haben, ist der Effekt der größte. In einem solchen Fall können Sie folgende Schritte ausführen:

  • prüfen Sie, ob die Datenbank, die Sie verwenden, die Anweisung PREPARE unterstützt. In den meisten Fällen wird es vorhanden sein.
  • vergewissern Sie sich, dass das von Ihnen verwendete Laufwerk vorbereitete Anweisungen unterstützt. Wenn nicht, versuchen Sie, ein anderes Laufwerk zu finden.
  • Überprüfen Sie die Unterstützung dieser Funktion auf ORM-Paketebene. Manchmal variiert der Treiber von Treiber zu Treiber (z. B. . Sqlalchemy gibt einige Einschränkungen für vorbereitete Anweisungen in MySQL an, da MySQL dies so verwaltet.). 

Wenn Sie auf der Suche nach einer wirklich autoritativen Antwort sind, würde ich zu Autoren der sqlalchemy gehen.

2
Jan Vlcinsky

Eine SQL-Anweisung kann nicht sofort ausgeführt werden: Das DBMS muss sie vor der Ausführung interpretieren.

Vorbereitete Anweisungen werden bereits interpretiert, die DBMS-Änderungsparameter und die Abfrage wird sofort gestartet. Dies ist eine Funktion bestimmter DBMS und Sie können eine schnelle Antwort erzielen (vergleichbar mit gespeicherten Prozeduren).

Parametrisierte Anweisungen sind nur eine Möglichkeit, die Abfragezeichenfolge in Ihren Programmiersprachen zu erstellen. Da es keine Rolle spielt, wie SQL-Zeichenfolgen gebildet werden, ist die Antwort von DBMS langsamer.

Wenn Sie die Zeit messen, in der dieselbe Abfrage 3-4 Mal ausgeführt wird (Auswahl mit unterschiedlichen Bedingungen), werden Sie dieselbe Zeit mit parametrisierten Abfragen sehen. Die Zeit ist mit der zweiten Ausführung der vorbereiteten Anweisung kürzer (das DBMS muss das Skript zum ersten Mal interpretieren sowieso).

0
Fil