7

mysqli_multi_query()@ Can mysqli_multi_query do UPDATE statement? ベスト プラクティスとは思えなかったからです。

ただし、Craig @ mysqli multi_query の後に query が続くmysqli_multi_query()場合、 を使用するよりも、 を使用するたびに切断して再接続する方が速いと述べていますmysqli_next_result()

プログラマーが「新しい接続」と「次の結果」のどちらの方法を選択する必要があるかについて、おおよその「カットオフ」(クエリの量などに基づく) を示唆する直接的な知識やベンチマークの証拠を誰かがさらに持っているかどうかを尋ねたいと思います。

また、速度に関係のないあらゆる懸念事項を喜んでお聞きします。Craig の接続関数の使用は、速度に関係がありますか?

クレイグの while ステートメントの間に速度の違いはありますか:

while ($mysqli->next_result()) {;}

- 対 -

私が提案しているwhileステートメント:

while(mysqli_more_results($mysqli) && mysqli_next_result($mysqli));

- 対 -

最初に実行する前に、予想される multi_query ごとに新しい接続を作成しmulti_queryます。これをテストしたところ、2つmysqli_multi_query()の s にエラーはありませんでした =close()必要ありません:

$mysqli1=mysqli_connect("$host","$user","$pass","$db");
$mysqli2=mysqli_connect("$host","$user","$pass","$db");

- 対 -

mysqli_multi_query()Sebastien と Craig のようなそれぞれの間の開始と終了:

$mysqli = newSQL();
$mysqli->multi_query($multiUpdates);
$mysqli->close();

- 対 -

テストする別のオプションがある人はいますか?

4

2 に答える 2

10

それはnext_result()自分のせいではなく、自分自身に問いかけます。コードの実行にかかる時間は、実際のクエリの実行にかかる時間に依存します。

mysqli_multi_query()コントロールは非常に高速に返されますが、それまでにすべてのクエリが実行されたわけではありません。まったく逆に、mysqli_multi_query()終了するまでに、 最初のクエリのみが実行されました。他のすべてのクエリは、非同期実行 のために mysql 側でキューに入れられます。

next_result()このことから、呼び出し自体はタイムアウトを追加しないと結論付けることができます。次のクエリが終了するのを待っているだけです。また、クエリ自体に時間がかかる場合はnext_result()、同様に待機する必要があります。

どの方法を選択するかはすでにわかっているかもしれませんが、結果を気にしない場合は、接続を閉じるだけでかまいません。しかし実際には、ラグの下の汚れを一掃するだけで、すべての低速クエリがそのまま残ります。したがって、next_result()ループを維持することをお勧めします (特に、エラー/影響を受ける行/などをチェックする必要があるため) が、クエリ自体を高速化します。

したがって、問題を解決するnext_result()には、クエリ速度の通常の問題を実際に解決する必要があることがわかりました。したがって、ここにいくつかの推奨事項があります。

  1. 選択クエリの場合、他の回答で既に説明されている通常のインデックス作成/分析の説明です。
  2. 特にバッチで実行される DML クエリの場合、他の方法があります。

Craig のケースについて言えば、innodb の書き込み速度に関する既知の問題によく似ています。デフォルトでは、innodb エンジンは非常に慎重なモードに設定されており、エンジンが前の書き込みが正常に完了したことを確認するまで、次の書き込みは実行されません。そのため、書き込みが非常に遅くなります (1 秒あたりわずか 10 クエリ程度)。これに対する一般的な回避策は、すべての書き込みを一度に行うことです。挿入クエリには、多くのメソッドがあります。

  • 複数の値の挿入構文を使用できます
  • LOAD DATA INFILE クエリを使用できます
  • すべてのクエリをトランザクションでラップできます。

トランザクションのみを更新および削除する場合は、信頼できる方法のままです。したがって、普遍的な解決策として、そのような回避策を提供できます

 $multiSQL = "BEGIN;{$multiSQL}COMMIT;";
 $mysqli->multi_query($multiSQL);
 while ($mysqli->next_result()) {/* check results here */}

あなたのケースで機能しない/適用できない場合はmysqli_multi_query()、ループで実行される単一のクエリに変更し、速度を調査して最適化し、multi_query に戻ることをお勧めします。

于 2014-03-20T13:41:45.313 に答える
4

あなたの質問に答えるには:

ジャンプする前に見る

あなたのmysqli_more_results()呼び出し (ジャンプする前の外観) はスピードアップしないと思います: n 件の結果がある場合、データベースに対して (2*n)-1 回の呼び出しを行いますが、Craig は n+1 回の呼び出しを行います。

複数の接続

multi_query asyncを実行するので、接続オーバーヘッドを追加するだけです。

データベースの開閉

あなたの常識に耳を傾けてください;-) しかし、あなたがしていることを見失わないでください。クエリをトランザクションにラップすると、アトミックになります。つまり、それらはすべて失敗するか、すべて成功します。データベースがあなたの言説の宇宙と衝突しないようにするために、時にはそれが必要です。しかし、高速化のためにトランザクションを使用すると、望ましくない副作用が生じる可能性があります。クエリの1 つが制約に違反している場合を考えてみましょう。これにより、トランザクション全体が失敗します。つまり、そもそもそれらが論理的なトランザクションではなく、ほとんどのクエリが成功するはずだった場合、どれが間違っていて、どれを再発行する必要があるかを見つけなければならないということです。原価計算スピードアップを提供する代わりに、より多くのことを行います。

Sebastienのクエリは、実際には、親の削除または更新を含む、より大きなトランザクションの一部であるように見えます。

代わりに、試して覚えてください

スプーンがない

あなたの例では、複数のクエリは必要ありませんでした。INSERT ... VALUESフォームは、VALUES に複数のタプルを取ります。したがって、1 つの準備されたステートメントを準備し、その繰り返し実行をトランザクションでラップする代わりに、あなたの常識が示唆するようにします。単一のステートメントを準備し、それを実行して自動コミットすることができます。mysqliマニュアルによると、これにより一連のラウンドトリップが節約されます。

したがって、次の形式の SQL ステートメントを作成します。

INSERT INTO r (a, b, c) VALUES (?, ?, ?), (?, ?, ?), ...

バインドして実行します。mysqldump --optがそれを行うので、そうしないのはなぜですか? ステートメントの最適化に関するセクションとしての mysql リファレンス マニュアル。挿入クエリと更新クエリについては、DML セクションを参照してください。しかし、それが何をするのかを理解する--optことは良い出発点です。

声明を準備することの過小評価された価値

私にとって、準備済みステートメントの真の価値は、複数回実行できることではなく、自動入力エスケープですわずか 1 回の追加のクライアント サーバー ラウンドトリップで、SQL インジェクションから身を守ることができます。を使用している場合は特に、SQL インジェクションは重大な注意点ですmulti_query。複数のクエリを想定して実行するmulti_queryように mysql に指示します。したがって、適切に脱出できなかった場合は、楽しい時間を過ごすことができます。

ママの功績

したがって、私のベストプラクティスは次のとおりです。

  1. 本当に複数のクエリが必要ですか?
  2. もしそうなら、うまく逃げるか、準備してください!
于 2014-03-28T11:25:44.780 に答える