1

I'm current writing an application that has to execute the same query many times. The query has a (potentially large) array as parameter, and looks like:

SELECT 
  m.a, SUM(m.b) as b, SUM(m.c) as c, SUM(m.d) as d
FROM table_m m JOIN table_k k ON (k.x IN %s AND k.id = m.y)
WHERE m.b > 0
GROUP BY m.a

I'm using Psycopg2 on Postgresql 9.1. For each query I create a new cursor and execute() the query with a list of numbers as parameter (the query is execute around 5000 times in my test cast). The length of the input list varies from anywhere between 1 and 5000 items.

On average the query takes slightly under 50ms to run, with the slowest execution taking around 500ms.

I have two questions about this:

  • Is there anything I can do to optimize this query?
  • Is there any way to prepare the query once, and execute it many times (or is Psycopg2 doing this internally)?

Schema for table_k

    Column     |  Type  | Modifiers 
---------------+--------+-----------
 id           | bigint | not null
 x            | bigint | 
Indexes:
    "table_k_pkey" PRIMARY KEY, btree (id)
    "table_k_id_x_idx" btree (id, x)
    "table_k_x_idx" btree (x)

Schema for table_m

      Column        |            Type             | Modifiers 
---------------------+-----------------------------+-----------
 id                  | bigint                      | not null
 y                   | bigint                      | 
 a                   | bigint                      | 
 b                   | integer                     | 
 c                   | integer                     | 
 d                   | double precision            | 
Indexes:
    "table_m_pkey" PRIMARY KEY, btree (id)
    "table_m_y_idx" hash (y)
    "table_m_a_idx" btree (a)
    "table_m_b_idx" btree (b)

Hope this is enough information.

4

2 に答える 2

1

オプティマイザーが正確に賢くなく、IN必要以上に多くの時間を評価している可能性があります。サブクエリに移動してみてください:

SELECT 
  m.a, SUM(m.b) as b, SUM(m.c) as c, SUM(m.d) as d
FROM table_m m 
JOIN 
(
    SELECT *
    FROM table_k
    WHERE x IN %s
) k ON k.id = m.y
WHERE m.b > 0
GROUP BY m.a

IN最初に長いリストを使用すると、パフォーマンスが低下する可能性もあります。一時テーブルを作成し、検索する値を挿入してから、一時テーブルに結合してみてください。

于 2013-01-26T11:47:10.043 に答える
0
  1. 最初の質問に答えるにはEXPLAIN (analyze)、最も速いクエリと最も遅いクエリの出力を表示する必要があります。現在のクエリの外観に重要なことは何もありません。

  2. はい、後で実行するためPREPAREにクエリを実行することは可能です。ドキュメントの引用:

準備済みステートメントは、パフォーマンスを最適化するために使用できるサーバー側のオブジェクトです。PREPARE ステートメントが実行されると、指定されたステートメントが解析、分析、および書き換えられます。その後、EXECUTE コマンドが発行されると、準備済みステートメントが計画され、実行されます。この分業により、実行計画が指定された特定のパラメーター値に依存することを可能にしながら、反復的な解析分析作業が回避されます。

PREPARE注意してください (ドキュメントにも記載されています)、小さなステートメントを ingしてもあまり利益が得られないことに注意してください。

また、クエリが異なるセッションで実行された場合、パフォーマンスが向上することはありません。PostgreSQL には、事前に作成されたステートメントをセッション間で共有するためのインフラストラクチャがないためです。

クエリを頻繁に実行し、たまたま等しい入力で実行する場合は、アプリケーションまたは専用のデータベース テーブルのいずれかに結果のキャッシュを整理することをお勧めします。配列は、キャッシュ ルックアップに最適なキーのようです。

于 2013-01-30T07:15:06.657 に答える