2013-01-04 2 views
7

ここでは簡単なテストを行い、MySQL PDOのプリペアドステートメントとストレートクエリを使用した場合のパフォーマンスペナルティを簡単に知ることができます。人のテーブルには2801の行があります。 MySQLバージョン5.5.28およびPHPバージョン5.3.15。デフォルトパラメータが何であれ、バニラのインストール。テストは8GBのiMacで実行されます。まったくのペナルティを示していないMySQL PDOはクエリよりも速く準備されていますか?これは単純なテストの結果です

query: 21.010436058044 

prepare/execute: 20.74036192894 

$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); 

、これが出力しました。可能性:

  • 準備されたステートメントのキャッシュは実際に動作しています。 (私は準備関数をループ内に保っていたことに注意してください)

  • これは単純すぎるので偽のテストです。

  • MySQL/PDO/PHP開発者は、準備/実行が遅くなければならず、絶え間ない批判に疲れているという理論的理由はありません。私たち全員を黙らせようとして。

  • その他?

プリペアドステートメントを使用してクエリを使用するよりも安全であると、PDO(のMysqliがそれらを持っていない)の名前付きパラメータを使用して、パラメータを扱うことはかなり便利であることを、ここで何度も言われています。しかし、それが実行されるたびに文が準備されなければならない場合には、パフォーマンスのペナルティがあることに注意してください。

誰かが私の簡単なテストに矛盾するいくつかのテストを提供することができますか?あるいは、準備された声明を使わない理由はないと認めますか?

+2

1)恐ろしい2)はい3)「誰が気にしますか?」 - 準備されたステートメントを使用する。 –

+1

それだけの理由から、もう一度クエリを実行してみて、順序を入れ替えてみてください(最初に準備してください)。 – Supericy

+0

準備済みのステートメントは、準備されたステートメントのSQLが毎回同じであることを前提に、準備済みのステートメントがストレート・クエリーよりも_faster_であると予想されます。これにより、クエリ解析がデータベースサーバーにキャッシュされるようになります。これは、準備されていないWHERE句が常に変更されている場合は不可能です。 – halfer

答えて

4

私はあなたの方法でいくつかの問題があります。絶対に何もほとんどありませんスクリプトと同時に、サーバー上で実行されているが存在しない場合を除き

  1. を、あなたの初歩的なタイマーは、CPUの気まぐれの対象となりますスケジューリング、これに対処2つの別々スクリプトを記述しての* nixのtimeコマンド、すなわち使用してそれらを実行するには:time php myscript.php
  2. をスクリプトの順序を逆にMySQLがクエリをキャッシュするため、同じ結果を生成することがあります。
  3. 1つのテストでそれぞれ診断が行われません。各スクリプトを数百回、数千回実行してから結果を平均して、より包括的な結果を得てください。

しかし、あなたは厳密に時間のすべてと、まだは、SQLインジェクションの可能性を持つ、あなたのすべての入力を検証するのが好きない限り、非静的クエリの場合に準備された文を使用しないでする理由はまだありません。

+0

そして#4を発行してください:準備*内部*ループを行うことは愚かです。 – Charles

+2

これはprepare/executeのコストのタイミングテストなので、準備をループに入れないとテストが無効になります。 (これはタイミングテストであり、プログラムを書く方法のレシピではありません!) –

10

言及すべきことが少しあります。デフォルトでは、PDOはとなり、プリペアドステートメントがエミュレートされます。
そして、エミュレーションモードにある間、それは実際には単一の文を準備することなく、同じ古いクエリを実行します:)

だから、まず、

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

上の実際のプリペアドステートメントをオンにします。

同じように、多くの場合、パフォーマンスの低下はもちろんのこと、他の小さい事があり

があることを指摘しています。
悲しいことに、世界では実質の知識はごくわずかです。そして特にQ &サイトの世界で。人々は、読んだ情報を繰り返す傾向があり、合理的であると感じました。証明するために、あるいは手を掛けなくても、テストを実行する必要はありません。だから、「しばしば注目される」は信頼できる情報源とはみなされるべきではない。

問題に戻る:ある程度のペナルティが必要ですが、ほとんどの時間はそれほど重要ではありません。もしそうなら、システムを調整する必要があります。

いずれにしても、エミュレーションモードでは「高速」かつ安全です。

更新
まあ、私のデータでテストを実行した後、私はあなたが大規模なデータセットの3倍差がある場合は、データベースに問題があることを言うようになってきました。雷クエリの

select title from Board where id = 1 

結果は

emulation on  off 
query  0.07 0.130 
prepare 0.075 0.145 

かなり厄介クエリの

select title from Board where id > 1 

結果であるが

emulation on  off 
query  0.96 0.96 
prepare 0.96 1.00 

これまでのように、大きなデータセットでは違いが目立たなくなります。

雷のクエリにはいくつかの違いがありますが、1回のクエリで2番目の派閥の0,0003番目の派閥しかないため、「無関心」という言葉の完全な例です。

query()/ prepare()との間の結果は同じです。PDOはバインディングのないものでもすべてのクエリに対してprepare/executeを使用します。

エンコードの問題が発生しました。

はい、変わったGBKの問題は、5.3.3以前のバージョンのPDOに影響します。これらのバージョンは、適切なエンコーディングを設定する方法がなく、避けられない脆弱性がありました(エミュレーションモード)。しかし、5.3.3 PDOはDSNでのエンコーディングの設定をサポートしているので、今ではすべてが正しいです。
mysqliの場合、まったく同じ(侵入不可能な)結果で、この目的のためにmysqli_set_charset()を使用しなければなりません。

私自身のクラスでは、mysqliに基づいています。私は自分のプレースホルダ実装を使用しており、準備済みの文を一切使用していません。パフォーマンスの理由ではなく、信頼性の向上に役立ちます。

+0

非常に良い点。私がそれをオフにすると、時間は彼らのものの約3分の1に低下します。しかし、それは準備されたケースと準備されていないケースの両方に当てはまります。しかし、順序は入れ替えられます:準備が整った髪が早くなるのではなく、今や髪が遅くなりました。 (通りの言葉は、準備が実質的に遅いので、私は、私が取得している時間を、7.5秒対7.3秒、200回の反復 - ネクタイと呼んでいる) –

+0

エミュレーションに関する質問: real_escape_string関数は、慎重に使用する場合でも、奇妙な文字エンコーディングの問題が依然としてセキュリティ上の問題を引き起こす可能性があります。 (これはいくつかの機会にここに掲載されています)。準備されたステートメントのPDOエミュレーションは完全に弾丸であるか、real_escape_string(mysqli)やquote(PDO)を使用するよりも良くないですか? –

+0

テストを実行したMySQLのバージョンは何ですか? – meze

関連する問題