2013-01-04 7 views
7

Hier ist ein einfacher Test, den ich lief, um eine schnelle Vorstellung der Leistungseinbuße zu erhalten, die ich für die Verwendung von MySQL PDO vorbereiteten Aussagen im Vergleich zu einer direkten Abfrage zahlen würde. In der Personentabelle gibt es 2801 Zeilen. MySQL Version 5.5.28 und PHP Version 5.3.15. Vanille-Installationen, mit welchen Standard-Parametern auch immer. Tests laufen auf einem iMac mit 8 GB.MySQL PDO schneller vorbereitet als Abfrage? Das ist, was dieser einfache Test zeigt

$pdo = new PDO('mysql:host=localhost;dbname=cwadb_local', 'root', ""); 
$start = microtime(true); 
for ($i = 0; $i < 200; $i++) { 
    $pdo->query("select * from person where name_last = 'smith' or true"); 
} 
echo "<p>query: " . (microtime(true) - $start); 

$start = microtime(true); 
for ($i = 0; $i < 200; $i++) { 
    $stmt = $pdo->prepare("select * from person where name_last = :last or true"); 
    $stmt->execute(array('last' => 'smith')); 
} 
echo "<p>prepare/execute: " . (microtime(true) - $start); 

und dies war die Ausgabe:

query: 21.010436058044 

prepare/execute: 20.74036192894 

, die überhaupt keine Strafe zeigt. Möglichkeiten:

  • Caching der vorbereiteten Anweisung funktioniert wirklich. (Beachten Sie, dass ich die Vorbereitungsfunktion innerhalb der Schleife beibehalten habe.)

  • Es ist ein Scheintest, weil es zu einfach ist.

  • Es gibt keinen theoretischen Grund, warum prepare/execute langsamer sein sollte, und die Entwickler von MySQL/PDO/PHP haben sich die Mühe gemacht, sie schneller zu machen, um uns alle zum Schweigen zu bringen .

  • Andere? viele Male hier gesagt worden, dass die Verwendung von vorbereiteten Anweisungen ist sicherer als Abfrage und mit den genannten Parametern in PDO

Es ist (Mysqli nicht, sie hat), mit den Parametern zu tun ziemlich bequem ist. Aber es wird genauso oft angemerkt, dass es eine Leistungseinbuße gibt, wenn die Anweisung bei jeder Ausführung vorbereitet werden muss.

Kann jemand also einige Tests liefern, die meinem einfachen Test widersprechen? Oder sollen wir gerade zugeben, dass es keinen Grund gibt, keine vorbereiteten Aussagen zu verwenden?

+2

1) Super 2) Ja 3) "Wen interessiert's?" - Verwenden Sie vorbereitete Aussagen. –

+1

Nur um es zu versuchen, versuchen Sie es erneut mit mehr Abfragen und versuchen Sie auch, die Reihenfolge zu tauschen (zuerst vorbereitet). – Supericy

+0

Ich hätte gedacht, dass vorbereitete Anweisungen _faster_ als direkte Abfragen erwartet werden, auf der Grundlage, dass das SQL in der vorbereiteten Anweisung jedes Mal dasselbe ist. Dadurch kann die Abfrageanalyse im Datenbankserver zwischengespeichert werden. Dies ist nicht möglich, wenn Sie nicht vorbereitete 'WHERE'-Klauseln ständig ändern. – halfer

Antwort

4

ich einige Probleme mit Ihrer Methodik haben:

  1. Es sei denn, es ist absolut nichts anderes zur gleichen Zeit wie das Skript auf dem Server ausgeführt werden, bei denen es unwahrscheinlich ist, Ihre rudimentär Timer ist den Launen der CPU-Thema Planung. Um dem abzuhelfen, schreiben zwei separaten Skripte und führen sie mit * der nix time Befehl, das heißt: time php myscript.php
  2. die Reihenfolge der Skripte Umkehren kann die gleichen Ergebnisse aufgrund mySQL Caching der Abfrage generieren.
  3. Ein Test macht keine Diagnose. Versuchen Sie, jedes Skript einige hundert oder einige tausend Mal auszuführen und dann die Ergebnisse zu mitteln, um ein abgerundetes Ergebnis zu erhalten.

Aber es gibt noch keinen Grund, nicht bereit, Aussagen im Falle einer nicht-statische Abfrage zu verwenden, wenn Sie konsequent wie alle Ihre Eingaben die ganze Zeit und noch mit der Möglichkeit, SQL-Injection-Validierung.

+0

Und dann Frage # 4: macht die Vorbereitung * innen * die Schleife ist albern. – Charles

+2

Da dies ein Timing-Test der Kosten von prepare/execute ist, würde das Nichtvorlegen der Vorbereitung in die Schleife den Test ungültig machen. (Es ist ein Timing-Test, kein Rezept für das Schreiben von Programmen!) –

10

Es gibt eine kleine Sache zu erwähnen. Standardmäßig emuliert PDO nur vorbereitete Anweisungen.
Und während im Emulationsmodus läuft es die gleiche alte Abfrage, ohne tatsächlich

Also, zunächst einmal eine einzige Anweisung :) Vorbereitung

$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, FALSE); 

drehen echten vorbereitete Anweisungen auf.

es bemerkt ebenso oft, dass es

Es gibt eine andere Kleinigkeit zu erwähnen, eine Leistungseinbuße ist.
Leider gibt es sehr wenig echte Wissen in der Welt. Und vor allem in der Welt der Q & A Websites. Menschen neigen dazu, die Informationen zu wiederholen, die sie gelesen und für angemessen befunden haben. Ohne irgendwelche Tests zu machen, um es zu beweisen oder sogar ohne ihre Hände zu legen. Daher sollte "oft bemerkt" nicht als zuverlässige Quelle betrachtet werden.

Zurück zur Sache: obwohl es eine Strafe geben sollte, sollte es die meiste Zeit unbedeutend sein. Wenn es ist - müssen Sie Ihr System optimieren.

Wie auch immer, im Emulationsmodus haben Sie es sowohl "schnell" als auch sicher.

aktualisieren
Nun, nachdem die Tests auf meine Daten laufen, ich habe zu sagen, dass es etwas falsch mit Ihrer Datenbank, wenn Sie 3-mal Unterschied auf einer großen Datenmenge haben.

Für eine Blitzabfrage

select title from Board where id = 1 

Ergebnisse sind

emulation on  off 
query  0.07 0.130 
prepare 0.075 0.145 

während für die recht beschwerlich Abfrage

select title from Board where id > 1 

Ergebnisse sind

emulation on  off 
query  0.96 0.96 
prepare 0.96 1.00 

So, wie wir sehen können, auf einem großen Datensatz wird der Unterschied unmerklich.

Für die Blitzabfrage gibt es einige Unterschiede, aber da es nur 0,0003. Fraktion der Sekunde braucht (für eine einzige Abfrage) - würde ich sagen, das ist ein perfektes Beispiel für das Wort "Gleichgültigkeit".

Für die gleichen Ergebnisse zwischen query()/prepare() - Ich habe nur eine Idee - PDO verwendet prepare/execute für alle Abfragen, auch solche ohne Bindungen.

Jetzt zum Codierungs-Problem.

Ja, seltsames GBK-Problem betrifft PDO für Versionen vor 5.3.3. Diese Versionen hatten keine Möglichkeit, die richtige Kodierung einzustellen und waren unvermeidbar anfällig (im Emulationsmodus). Aber seit 5.3.3 PDO unterstützt das Einstellen der Codierung in DSN, und jetzt ist alles in Ordnung.
Für mysqli muss man mysqli_set_charset() für genau diesen Zweck mit dem gleichen (undurchdringlichen) Ergebnis verwenden.

In meiner eigenen Klasse, die auf mysqli basiert, verwende ich meine eigene Platzhalter-Implementierung und verwende keine vorbereiteten Anweisungen. Nicht aus Leistungsgründen, aber für eine bessere Zuverlässigkeit.

+0

Sehr guter Punkt. Wenn ich es ausschalte, fallen die Zeiten auf etwa ein Drittel von dem, was sie waren. Aber ... das gilt sowohl für die vorbereiteten als auch für die nicht vorbereiteten Fälle. Die Reihenfolge ist jedoch vertauscht: Anstatt ein Haar schneller zu präparieren, ist es jetzt ein Haar langsamer. (Das Wort auf der Straße ist, dass vorbereitet ist wesentlich langsamer, so rufe ich die Zeiten, die ich bekomme - 7,5 Sekunden vs. 7,3 Sekunden für 200 Iterationen - ein Unentschieden.) –

+0

Frage zu Emulation: Ein Problem mit der Real_escape_string-Funktion, auch wenn sie peinlich genau verwendet wird, ist, dass seltsame Zeichencodierungsprobleme immer noch zu einer Sicherheitslücke führen können. (Dies wurde hier bei einigen Gelegenheiten veröffentlicht.) Ist die PDO-Emulation von vorbereiteten Anweisungen daher vollständig kugelsicher, oder ist es nicht besser oder schlechter als die Verwendung von real_escape_string (mysqli) oder Zitat (PDO)? –

+0

In welcher Version von MySQL haben Sie Ihre Tests durchgeführt? – meze

Verwandte Themen