PDO: Cache von Prepared Statements

PDO: Cache von Prepared Statements

am 29.01.2008 18:58:13 von steffen bruentjen

Hallo,

Prepared Statements haben neben dem Schutz vor SQL-Injections noch den
Vorteil, dass ihre Optimierung nur einmalig vom Server durchgeführt
werden muss. Nun ist es so, dass ein solches optimiertes
Statement-Objekt im Allgemeinen in einer Methode erzeugt und dort so
oft wie eben nötig ausgeführt wird. Wenn die Methode verlassen und zu
einem späteren Zeitpunkt nochmal aufgerufen wird, muss das
Statement-Objekt neu erzeugt werden. Es stellt sich nun die Frage, ob
DBMSs optimierte Statements intern cachen und bei erneutem Aufruf eine
gecachte Version des bereits optimierten Statements zurückliefern.
Dies wäre sehr effizient, da die Optimierung unabhängig vom jeweiligen
Client laufen würde. Das scheint allerdings (zumindest bei MySQL) so
nicht zu sein, denn im MySQL-Handbuch steht über die C-API:

"The server parses the statement and sends the okay status back to the
client by assigning a statement ID. [...] All syntax and semantics of
the statement are checked by the server during this call.
The client uses this statement ID for the further operations, so that
the server can identify the statement from among its pool of
statements."

Unterschiedliche Clients erhalten also stets unterschiedliche
Statement IDs (was gleichbedeutend damit ist, dass nur clientbezogen
optimiert wird).

Warum wird das so gehandhabt?

Nun könnte die PDO-Erweiterung noch die Zuordnung von einer SQL-Query
zur Statement ID selbst verwalten. Im Quelltext von PDO hab ich dazu
nichts finden können. Eine eigene Klasse könnte etwa so aussehen:

class PDOWhatever extends PDO
{
private $stmtCache = array();

function prepare($sql, $options = array())
{
if (!isset($this->stmtCache[$sql]) ||
!is_object($this->stmtCache[$sql]))
{
$this->stmtCache[$sql] = parent::prepare($sql, $options);
}
return $this->stmtCache[$sql];
}

function clearStmtCache($sql)
{
if (isset($this->stmtCache[$sql]))
{
unset($this->stmtCache[$sql]);
}
}
}

Diese Unterklasse würde optimierte Statement-Objekte automatisch
zwischenspeichern und diese bei erneuter Anfrage (genauer: bei jeder
Anfrage mit identischem SQL-String) zurückliefern. clearStmtCache()
kann z.B. nötig sein, wenn sich Optionen ändern. Der Cache bleibt
allerdings natürlich client- und laufzeitspezifisch.

Meiner Meinung nach erübrigen sich damit die Vorteile der prepared
Statements; zum einen wegen des fehlenden Query Cache, zum anderen
weil die prepared Statements nicht wiederverwendet werden.

Mit dem angekündigten PHP-eigenen Treiber für MySQL, welcher sowohl
einen Prepared Statement Cache als auch Query Cache auf Client-Seite
unterstützen soll, werden sich diese Probleme wohl selbst erledigt
haben, aber der braucht ja noch ein wenig.

Weiß jemand noch etwas darüber?


Schöne Grüße, Steffen

--
Das Tastaturlayout für Programmierer:
http://eurkey.steffen.bruentjen.eu

Re: PDO: Cache von Prepared Statements

am 29.01.2008 19:30:48 von Christoph Herrmann

steffen bruentjen schrieb:
> function prepare($sql, $options = array())
> {
> if (!isset($this->stmtCache[$sql]) ||
> !is_object($this->stmtCache[$sql]))

Wofür prüfen, ob es sich um ein Objekt handelt?

> Diese Unterklasse würde optimierte Statement-Objekte automatisch
> zwischenspeichern und diese bei erneuter Anfrage (genauer: bei jeder
> Anfrage mit identischem SQL-String) zurückliefern. clearStmtCache()
> kann z.B. nötig sein, wenn sich Optionen ändern. Der Cache bleibt
> allerdings natürlich client- und laufzeitspezifisch.
>
> Meiner Meinung nach erübrigen sich damit die Vorteile der prepared
> Statements; zum einen wegen des fehlenden Query Cache, zum anderen
> weil die prepared Statements nicht wiederverwendet werden.

Solange das Objekt existiert werden diese wiederverwendet. Außerdem ist
das automatische Maskieren für viele der größere Vorteil und sollte
nicht außer acht gelassen werden. Ein Cache wäre vielleicht sinnvoll,
aber dann über ein Seitenaufruf hinweg eher. Da stellt sich nur die
Frage, ob sich der benötigte Platz zum Speichern der optimierten
Statements lohnt im Gegenzug zur gewonnenen Performance.

--
Mit freundlichen Grüßen,
Christoph Herrmann

http://dragonprojects.de/

Re: PDO: Cache von Prepared Statements

am 29.01.2008 20:20:31 von Axel Schwenke

steffen bruentjen wrote:
>=20
> Prepared Statements haben neben dem Schutz vor SQL-Injections noch den
> Vorteil, dass ihre Optimierung nur einmalig vom Server durchgeführt
> werden muss. Nun ist es so, dass ein solches optimiertes
> Statement-Objekt im Allgemeinen in einer Methode erzeugt und dort so
> oft wie eben nötig ausgeführt wird. Wenn die Methode verlassen und =
zu
> einem späteren Zeitpunkt nochmal aufgerufen wird, muss das
> Statement-Objekt neu erzeugt werden. Es stellt sich nun die Frage, ob
> DBMSs optimierte Statements intern cachen und bei erneutem Aufruf eine
> gecachte Version des bereits optimierten Statements zurückliefern.
> Dies wäre sehr effizient, da die Optimierung unabhängig vom jeweili=
gen
> Client laufen würde. Das scheint allerdings (zumindest bei MySQL) so
> nicht zu sein, denn im MySQL-Handbuch steht über die C-API:
>=20
> "The server parses the statement and sends the okay status back to the
> client by assigning a statement ID. [...] All syntax and semantics of
> the statement are checked by the server during this call.
> The client uses this statement ID for the further operations, so that
> the server can identify the statement from among its pool of
> statements."
>=20
> Unterschiedliche Clients erhalten also stets unterschiedliche
> Statement IDs (was gleichbedeutend damit ist, dass nur clientbezogen
> optimiert wird).
>=20
> Warum wird das so gehandhabt?

Weil MySQL im Gegensatz zu anderen DBMS den Ausführungsplan für das
Statement nicht in der Prepare- sondern in der Execute-Phase bestimmt.
Das vermindert den Wert eines Caches für das präparierte Statement
erheblich, hat aber den Vorteil, daß der Optimizer ein paar Möglichke=
iten
mehr hat.

> Nun könnte die PDO-Erweiterung noch die Zuordnung von einer SQL-Query=

> zur Statement ID selbst verwalten.
..

Ich weiß von zumindest einem (nicht öffentlichen) Projekt, wo ein Cac=
he
dieser Art implementiert wurde; pro Connection ein Pool von prepared
Statements Handles, die bei Bedarf wieder verwendet wurden. Der Gewinn du=
rch
einen solchen Cache ist eher bescheiden. Caching auf Resultat-Ebene (a'la=

Query-Cache) bringt wesentlich mehr.


XL
--=20
In der klassischen Kryptographie verschlüsselt Alice Nachrichten an Bob=
um
sie vor Carol zu schützen. Bei DRM sind Bob und Carol die gleiche Perso=
n.

Re: PDO: Cache von Prepared Statements

am 29.01.2008 20:33:58 von steffen bruentjen

Christoph Herrmann wrote:
>steffen bruentjen schrieb:
>> function prepare($sql, $options = array())
>> {
>> if (!isset($this->stmtCache[$sql]) ||
>> !is_object($this->stmtCache[$sql]))
>
>Wofür prüfen, ob es sich um ein Objekt handelt?

Wenn die Datenbank aus irgendeinem Grund die Anfrage nicht verarbeiten
kann, wird FALSE zurückgeliefert. Das kann, wenn sich beispielsweise
das Schema ändert, bei der nächsten, gleichen Anfrage anders sein.

Man könnte die optimierten Statements auch manuell clientseitig
speichern [zum Beispiel in einer Datenbank :-)] und diese für alle
Zugriffe gleichermaßen verwenden.

>> Diese Unterklasse würde optimierte Statement-Objekte automatisch
>> zwischenspeichern und diese bei erneuter Anfrage (genauer: bei jeder
>> Anfrage mit identischem SQL-String) zurückliefern. clearStmtCache()
>> kann z.B. nötig sein, wenn sich Optionen ändern. Der Cache bleibt
>> allerdings natürlich client- und laufzeitspezifisch.
>>
>> Meiner Meinung nach erübrigen sich damit die Vorteile der prepared
>> Statements; zum einen wegen des fehlenden Query Cache, zum anderen
>> weil die prepared Statements nicht wiederverwendet werden.
>
>Solange das Objekt existiert werden diese wiederverwendet. Außerdem ist
>das automatische Maskieren für viele der größere Vorteil und sollte
>nicht außer acht gelassen werden. Ein Cache wäre vielleicht sinnvoll,
>aber dann über ein Seitenaufruf hinweg eher. Da stellt sich nur die
>Frage, ob sich der benötigte Platz zum Speichern der optimierten
>Statements lohnt im Gegenzug zur gewonnenen Performance.

Prepared Statements werden so häufig durch die mit ihnen einhergehende
Performance-Verbesserung motiviert. Ich konnte das vor allem wegen des
Wegfalls des Query Cache nicht nachvollziehen und suche deshalb nach
Hinweisen dazu.

Schöne Grüße, Steffen

--
Das Tastaturlayout für Programmierer:
http://eurkey.steffen.bruentjen.eu

Re: PDO: Cache von Prepared Statements

am 29.01.2008 20:47:27 von Christoph Herrmann

steffen bruentjen schrieb:
> Wenn die Datenbank aus irgendeinem Grund die Anfrage nicht verarbeiten
> kann, wird FALSE zurückgeliefert. Das kann, wenn sich beispielsweise
> das Schema ändert, bei der nächsten, gleichen Anfrage anders sein.

Hätte jetzt eher in der Methode abgefangen, sodass immer nur Statement
Objekte in der Liste stehen hast:

function prepare($sql, $options = array())
{
if (!isset($this->stmtCache[$sql]))
{
if($stmt = parent::prepare($sql, $options))
{
$this->stmtCache[$sql] = $stmt;
} else
{
return false;
}
}
return $this->stmtCache[$sql];
}

Aber ist sicherlich Geschmackssache. :)

> Prepared Statements werden so häufig durch die mit ihnen einhergehende
> Performance-Verbesserung motiviert. Ich konnte das vor allem wegen des
> Wegfalls des Query Cache nicht nachvollziehen und suche deshalb nach
> Hinweisen dazu.

Haben Sie ja auch so, vor allem wenn man innerhalb einer Methode oder
Allgemein mit einem Statement mehrere hunderte oder tausende
Ausführungen macht.

Aber hast natürlich Recht, das Ganze auch über die Lebensdauer hinweg zu
cachen hätte weitere Performancevorteile. Aber halt auch Nachteile wegen
Platzbedarf, deswegen würde ich es nicht generell nutzen, sondern nur
für Statements, die sehr oft (bei jedem Aufruf) benötigt werden.

--
Mit freundlichen Grüßen,
Christoph Herrmann

http://dragonprojects.de/

Re: PDO: Cache von Prepared Statements

am 29.01.2008 20:51:53 von steffen bruentjen

Axel Schwenke wrote:
>steffen bruentjen wrote:
>
>> Nun könnte die PDO-Erweiterung noch die Zuordnung von einer SQL-Query
>> zur Statement ID selbst verwalten.
>...
>
>Ich weiß von zumindest einem (nicht öffentlichen) Projekt, wo ein Cache
>dieser Art implementiert wurde; pro Connection ein Pool von prepared
>Statements Handles, die bei Bedarf wieder verwendet wurden. Der Gewinn durch
>einen solchen Cache ist eher bescheiden. Caching auf Resultat-Ebene (a'la
>Query-Cache) bringt wesentlich mehr.

Deshalb bin ich so verwundert. 'Prepared Statements ohne Cache' vs.
'Query Cache'. Aber gut, wenn das nur bei MySQL der Fall ist (und
selbst dort anscheinend bald behoben sein wird), soll das nicht weiter
stören.

Danke für die Antwort & schöne Grüße, Steffen

--
Das Tastaturlayout für Programmierer:
http://eurkey.steffen.bruentjen.eu