PostgreSQLに関する質問です。テーブルAとテーブルBがあり、テーブルAに47800件、テーブルBに232879件レコードが入っています。

この時
 explain analyze select a.name, b.code from table_a a left outer join table_b b on a.key = b.key limit 100;
とすると、
Limit (cost=0.00..1282.63 rows=100 width=126) (actual time=0.874..16107.458 rows=100 loops=1)
-> Nested Loop Left Join (cost=0.00..713884715.50 rows=55658081 width=126) (actual time=0.871..16107.138 rows=100 loops=1)
Join Filter: ((a.key)::text = (b.key)::text)
-> Seq Scan on table_a a (cost=0.00..2351.00 rows=47800 width=126) (actual time=0.008..0.082 rows=36 loops=1)
-> Seq Scan on talbe_b b (cost=0.00..12023.79 rows=232879 width=96) (actual time=0.015..275.220 rows=138650 loops=36)
という結果になりました。
この「rows=47800」は47800回分の結合を行っているという事でしょうか?
そうであればパフォーマンス向上の手段はありませんか?

回答の条件
  • URL必須
  • 1人3回まで
  • 登録:
  • 終了:2009/01/25 22:00:40
※ 有料アンケート・ポイント付き質問機能は2023年2月28日に終了しました。

ベストアンサー

id:kn1967 No.1

回答回数2915ベストアンサー獲得回数301

ポイント100pt

table_a は rows=36 loops=1 とありますので

  ループは1回(1回だからループとは言わないけど便宜上)

  36レコードを利用。


talbe_b は rows=138650 loops=36 とありますので

  ループは36回(table_aのrows分だけ実施されたという事)

  138650 レコードを利用。


まず、

rows=55658081の部分が気になりますのでwhere条件を付加する等して

table_a の対象レコードを100以下に出来ないかを検討してみてください。


また、Index Scan ではなく Seq Scan ということは

indexが利用されていない(もしくは存在しない)模様ですが

まず table_b の key に indexを作成してEXPLAINを実施し

さらに table_a の key にも indexを作成して比較してみてください。

index はすでに付けてあるということであれば

keyフィールドを対象にしたwhere条件を付加してみてください。


URL必須という事なので、ひとまずマニュアルを・・・。

http://www.postgresql.jp/document/pg835doc/html/using-explain.ht...

id:snaa1d_1

ありがとうございます。

色々と私自身が誤解しているところもあったようです。。

長くなりそうなのでコメントにかきますね。

2009/01/24 11:36:50
  • id:snaa1d_1
    すいません、はてなの文字数制限によりかなり短縮してしまったので補足します。。
    分かりにくいかと思いますが、rows=47800 の部分が何故気になるかというと、
    limit 100 をつけているため rows=100 とならなければ変では?と思ったのです。
    Pear::Pagerを使っているのですが、画面の反応が遅いため、少し気がかりになり質問した次第です。
  • id:snaa1d_1
    kn1967 さんへのご回答です。ご丁寧な回答、本当にありがとうございました。

    whereで100件以下に絞ったSQLを発行したところ、以下のようになりました(table_a の key カラムで絞込み、検索結果レコード数3件)

    Limit (cost=0.00..1084.32 rows=100 width=126) (actual time=0.272..141.335 rows=3 loops=1)
    -> Nested Loop Left Join (cost=0.00..3016525.42 rows=278196 width=126) (actual time=0.269..141.323 rows=3 loops=1)
    -> Index Scan using table_a_pkey on table_a a (cost=0.00..912.44 rows=239 width=126) (actual time=0.064..0.070 rows=1 loops=1)
    Index Cond: ((reader_code)::text = '950-4016-0-0199'::text)
    -> Seq Scan on table_b b (cost=0.00..12605.99 rows=1164 width=48) (actual time=0.199..141.234 rows=3 loops=1)
    Filter: ((reader_code)::text = '950-4016-0-0199'::text)
    Total runtime: 141.486 ms
    (7 rows)


    で、今回の質問は仕事の都合によりカラム名などは隠していたのですが、
    table_b の key カラムは Primary key ではなく通常のカラムです。
    よく見たところ、index を張っているつもりだったのですが、張っていなかったようです。。。

    そこでindexを張った後で上記と同じSQLを発行したところ

    Limit (cost=25.77..341.64 rows=100 width=126) (actual time=0.107..0.132 rows=3 loops=1)
    -> Nested Loop Left Join (cost=25.77..534517.61 rows=169212 width=126) (actual time=0.104..0.122 rows=3 loops=1)
    -> Index Scan using table_a_pkey on table_a a (cost=0.00..912.44 rows=239 width=126) (actual time=0.060..0.062 rows=1 loops=1)
    Index Cond: ((key)::text = 'xxx'::text)
    -> Bitmap Heap Scan on table_b b (cost=25.77..2225.58 rows=708 width=48) (actual time=0.036..0.044 rows=3 loops=1)
    Recheck Cond: ((key)::text = 'xxx'::text)
    -> Bitmap Index Scan on table_b_idx_01 (cost=0.00..25.59 rows=708 width=0) (actual time=0.029..0.029 rows=3 loops=1)
    Index Cond: ((key)::text = 'xxx'::text)
    Total runtime: 0.235 ms
    (9 rows)


    のように無事、インデックスを使うようになりました。
    インデックスを張っているものだという勘違いが原因で長い間苦しんでいたようです。
    ありがとうございました。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

回答リクエストを送信したユーザーはいません