web-dev-qa-db-ja.com

同じテーブルに複数回参加することは避けてください

2つのテーブルがあります。

CREATE TABLE one (
  id int4 primary key,
  p_id int4,
  k_id int4,
  c_id int4
);

CREATE TABLE two(
 id int4 primary key,
 p_id int4,
 k_id int4,
 t_id int4,
 pos int4
);

テーブルone:は結合テーブルです。このレポートでは、c_idと行数を制限するためにのみ使用しています。

テーブルtwo:には私のデータが含まれ、p_idk_idt_idには多くのposを含めることができるため、それらをグループ化し、min()を使用して最小posを取得します。 k_idp_idのすべてのデータを取得するいくつかの方法を試しました これが方法です (この解決策では、posで注文できませんでした) (フィドルを参照)

SELECT
  o.p_id,
  o.k_id,
  min(t.pos) as t_pos,
  min(t1.pos) as t1_pos
FROM one o
  LEFT JOIN two t ON t.p_id = o.p_id 
    AND t.k_id = o.k_id
    AND t.t_id = 1
  LEFT JOIN two t1 ON t1.p_id = o.p_id 
    AND t1.k_id = o.k_id
    AND t1.t_id = 2
WHERE o.p_id = 1 AND o.c_id = 1
GROUP BY 1, 2
LIMIT 1

このソリューションは2〜3倍遅くなります 他の投稿の@Erwin Brandstetterのソリューション ですが、t_post1_posの並べ替えが可能で、たとえばtype_id = 1pos = 1のすべてのデータも取得できます。

同じ出力を達成して速度を向上させ、データ(t_posおよびt1_pos列)をソートできるより良い方法はありますか?

3
RockNinja

これがどれだけ効果的か試してください

両方のt_idについて、テーブル2の1つの内部結合に左結合を変換しました。そして、minの計算では、caseステートメントを使用して、値t_idに基づいて2つの列に分割します。ここで保存するのは、テーブルを2回スキャンし、左結合と比較して内部結合です。

SELECT
    o.p_id,
    o.k_id,
    MIN(case when t.t_id = 1 then t.pos else null end) AS t_pos,
    MIN(case when t.t_id = 2 then t.pos else null end) AS t1_pos
FROM
    one o
INNER JOIN two T ON t.p_id = o.p_id
AND t.k_id = o.k_id
AND t.t_id =any ( 1,2)
WHERE
    o.p_id = 1
AND o.c_id = 1
GROUP BY
    1,
    2
LIMIT 1
1
Aneesh Mon N