2

PostgreSQL 9 バックエンドを使用するアプリケーションでスケーリングの問題が発生しています。サイズが約 4,000 万レコードで、成長している 1 つのテーブルがあり、それに対する条件付きクエリが劇的に遅くなりました。

何が問題なのかを把握するために、データベースの開発スナップショットを作成し、クエリと実行時間をログに記録しました。

さて、紛らわしい部分と質問の要点について....

ログ内のクエリの実行時間は、説明計画を取得するために DbVisualizer で「まったく同じ」クエリを実行した場合とは大きく異なります (桁違い +)。

「正確」と言いますが、実際の違いは、アプリケーションが実行時に値をバインドする準備済みステートメントを使用しているのに対し、DbVisualizer で実行するクエリにはそれらの値が既に配置されていることです。値自体は、ログから取得したものとまったく同じです。

準備済みステートメントを使用すると、それほど大きな違いが生じるでしょうか?

4

2 に答える 2

3

Erwinはそれを釘付けにしますが、拡張クエリプロトコルを使用すると、プリペアドステートメントのより多くのフレーバーを使用できることを付け加えておきます。再解析と再計画を回避することに加えて、プリペアドステートメントの大きな利点の1つは、パラメーター値を個別に送信することです。これにより、SQLインジェクションとバグの機会は言うまでもなく、処理するAPIを使用しない場合のエスケープと解析のオーバーヘッドが回避されます。あなたがそれらをエスケープすることを忘れることができない方法でパラメータ。

http://www.postgresql.org/docs/9.1/static/protocol-flow.html

名前付きプリペアドステートメントオブジェクトのクエリプランニングは、解析メッセージが処理されるときに発生します。クエリが異なるパラメータで繰り返し実行される場合は、パラメータ化されたクエリを含む単一の解析メッセージを送信し、その後に複数のバインドおよび実行メッセージを送信すると便利な場合があります。これにより、実行ごとにクエリを再計画する必要がなくなります。

名前のないプリペアドステートメントは、Parseメッセージでパラメーターが定義されていない場合、Parse処理中に同様に計画されます。ただし、パラメーターがある場合は、バインドパラメーターが指定されるたびにクエリプランニングが実行されます。これにより、プランナーは、一般的な見積もりを使用するのではなく、各バインドメッセージによって提供されるパラメーターの実際の値を利用できます。

したがって、DBインターフェースがそれをサポートしている場合は、名前のないプリペアドステートメントを使用できます。これは、クエリと通常のプリペアドステートメントの中間点です。

PHPをPDOで使用する場合、PDOのプリペアドステートメントの実装は、名前付きのプリペアドステートメントを使用するため、postgresにはあまり役に立ちませんが、prepare()を呼び出すたびに再準備されるため、プランのキャッシュは行われません。したがって、両方の中で最悪の事態が発生します。多くのラウンドトリップとパラメータなしの計画です。postgresオプティマイザーが最適なプランを作成するためにパラメーターを実際に知る必要がある特定のクエリでは、pg_query()およびpg_query_params()よりも1000倍遅いことがわかりました。pg_queryは生のクエリを使用し、pg_query_paramsは名前のないプリペアドステートメントを使用します。通常、一方は他方よりも高速ですが、これはパラメータデータのサイズによって異なります。

于 2012-02-02T21:59:26.093 に答える
3

答えはイエスです。準備されたステートメントは、両方の方法をカットします。

一方では、実行ごとにクエリを再計画する必要がないため、オーバーヘッドがいくらか節約されます。これは、クエリの複雑さに応じて、違いが生じるか、ほとんど目立たない場合があります。

一方、データの分散が不均一な場合、画一的なクエリ プランは不適切な選択になる可能性があります。特定の値を指定して呼び出すと、別のクエリ プランの方が (はるかに) 適している可能性があります。

パラメーター値を指定してクエリを実行すると、別のクエリ プランになる可能性があります。より多くの計画オーバーヘッド、おそらく (はるかに) 優れたクエリ プラン。

@peufeu providedのような名前のない準備済みステートメントも検討してください。それらは毎回パラメーターを考慮してクエリを再計画します-それでも安全なパラメーター処理があります。

PL/pgSQL 関数内のクエリにも同様の考慮事項が当てはまりますEXECUTEExecuting Dynamic Commandsに関するマニュアルを引用します。

重要な違いは、EXECUTE実行ごとにコマンドを再計画し、現在のパラメーター値に固有の計画を生成することです。一方、PL/pgSQL はそれ以外の場合、一般的なプランを作成し、再利用のためにキャッシュする場合があります。最適な計画がパラメータ値に大きく依存する状況ではEXECUTE、一般的な計画が選択されないようにするために を使用すると役立つ場合があります。

それとは別に、パフォーマンスの最適化に関する一般的なガイドラインが適用されます。

于 2012-02-02T17:54:52.193 に答える