[pgsql-jp: 36835] Re: 別テーブルを条件にしたUPDATEの性能(Re: WHEREにSELECTふたつ)
根岸 智幸
tomoyu-n @ tokyo-cafe.com
2006年 3月 7日 (火) 16:19:11 JST
こうもとさん
根岸です。
ベンチやExplainの結果をレポートしていただき、ありがとうご
ざいました。
僕も勉強になりました。
On 2006/03/07, at 15:27, 河本陽一 wrote:
> こうもとです。
>
> TANIDA Yutaka さんの書いたこと:
>> 谷田です。
>> お久しぶりです:)
>
> うわぉ。お久しぶりです。
>
>
>>> 案1(PostgreSQL専用):根岸さんと、海北さんの方法
>>> UPDATE t1 SET f3=f3+1
>>> FROM t2 WHERE t1.f1=t2.f1 AND t1.f2=t2.f2 AND t2.f5='a01';
>>>
>>> 案2(汎用):石田さんの方法
>>> UPDATE t1 SET f3=f3+1
>>> WHERE (f1,f2)=(SELECT f1,f2 FROM t2 WHERE f5='a01');
>>>
>>> 結果は、圧倒的に案1の方早いことがわかりました。
>>
>> explain analyzeの結果はどうなっていますか?あとanalyze
>> はしてますか?
>
> EXPLAIN ANALYZE の結果です。
>
> ●案1
> # EXPLAIN ANALYZE UPDATE t1 SET f3=f3+1 FROM t2 WHERE t1.f1=t2.f1
> AND t1.f2
> =t2.f2 AND t2.f5='text00019780';
> QUERY PLAN
> ----------------------------------------------------------------------
> ----------------------------------------------
> Nested Loop (cost=0.00..10.05 rows=1 width=18) (actual
> time=0.299..0.491 rows=1 loops=1)
> -> Index Scan using t2_f5_key on t2 (cost=0.00..3.01 rows=1
> width=8) (actual time=0.118..0.157 rows=1 loops=1)
> Index Cond: (f5 = 'text00019780'::text)
> -> Index Scan using t1_pkey on t1 (cost=0.00..7.01 rows=1
> width=18) (actual time=0.058..0.098 rows=1 loops=1)
> Index Cond: ((t1.f1 = "outer".f1) AND (t1.f2 = "outer".f2))
> Total runtime: 0.790 ms
> (6 rows)
>
> ●案2
> # EXPLAIN ANALYZE UPDATE t1 SET f3=f3+1 WHERE (f1,f2)=(SELECT f1,f2
> FROM t2 WHERE f5='text00019780');
> QUERY PLAN
> ----------------------------------------------------------------------
> ------------------------------------------------
> Seq Scan on t1 (cost=3.01..1766.52 rows=1 width=18) (actual
> time=518.590..518.650 rows=1 loops=1)
> Filter: ((f1 = $0) AND (f2 = $1))
> InitPlan
> -> Index Scan using t2_f5_key on t2 (cost=0.00..3.01 rows=1
> width=8) (actual time=5.275..5.318 rows=1 loops=1)
> Index Cond: (f5 = 'text00019780'::text)
> Total runtime: 519.751 ms
> (6 rows)
>
>
> ANALYZEは、Debianの場合、インストール時に自動で
> 定期的に実行するよ
> うになりました。
> #月曜から土曜の0,5,10,15,20時の2分に。
> ログにもANALYZEされた形跡が残っています。
>
>
>> たぶん案1は何かJOIN、案2は普通にループになっているの
>> ではと思います。で
>> あれば、案1が圧倒的に早いのは理の当然ではないかな、と思いま
>> す。
>
> 確かに、案2だとシーケンシャルアクセスになっているようです。
> これが時間のかかる原因だったのですね。
>
>
>> IN/NOT INを使った副問い合わせをより効率的に実行できるようにな
>> りました。
>> 7.3以前のバージョンではこれらの副問い合わせはより上位
>> の問い合わせとシー
>> ケンシャルスキャンを利用して結合するようにしていました。
>> 7.4ではたとえば
>> 副問い合わせを通常のJOINに変換するような方法で、これら
>> の検索は非常に高速
>> 化されました。
>
> これを見てふと思い、kuniyoshiさんの in を使う方
> 法を試してみると、
> こちらは早く終わりました。
>
> ●案2’
> # EXPLAIN ANALYZE UPDATE t1 SET f3=f3+1 WHERE (f1,f2)in(SELECT
> f1,f2 FROM t2 WHERE f5='text00019780');
> QUERY PLAN
> ----------------------------------------------------------------------
> ----------------------------------------------------
> Nested Loop (cost=3.02..10.05 rows=1 width=18) (actual
> time=0.412..0.602 rows=1 loops=1)
> -> HashAggregate (cost=3.02..3.02 rows=1 width=8) (actual
> time=0.233..0.270 rows=1 loops=1)
> -> Index Scan using t2_f5_key on t2 (cost=0.00..3.01
> rows=1 width=8) (actual time=0.073..0.112 rows=1 loops=1)
> Index Cond: (f5 = 'text00019780'::text)
> -> Index Scan using t1_pkey on t1 (cost=0.00..7.01 rows=1
> width=18) (actual time=0.057..0.096 rows=1 loops=1)
> Index Cond: ((t1.f1 = "outer".f1) AND (t1.f2 = "outer".f2))
> Total runtime: 0.873 ms
> (7 rows)
>
>
> 案1は、文句のつけようのない内容に思えます。頭で思った処理が
> そのま
> ま書いてある感じで気持ちがよいです。
> 案2は、t1を総なめし、その一つ一つでSELECTして条
> 件にあっているか調
> べているのでしょうか。
> 案2’は、複数(かもしれない)の結果から条件にあっ
> たものを取り出すた
> めに一度まとめ、それを元にt1を検索しているのでしょうか。
> 一度まとめる
> 手間はあるものの、ほとんど案1と同じ処理ですね。
>
> 結果としては、案2’の強烈な追い上げもわずかに届かず、案1の
> 優勝と
> いうことになりました。
>
>
> EXPLAINが、これほど役に立つコマンドとは思いませんでし
> た。
> これからは積極的に使っていこうと思います。
>
>
> ======================================================================
> 河本陽一(こうもとよういち)
> mailto:komoto.yoichi @ kcc.co.jp
>
>
>
>
pgsql-jp メーリングリストの案内