[pgsql-jp: 30357] Re: indexを使用しない/ 使用する違いは?
sugita @ sra.co.jp
sugita @ sra.co.jp
2003年 7月 3日 (木) 10:00:13 JST
杉田です。
From: Genshirou Taki <g_taki @ max-corporation.com>
Subject: [pgsql-jp: 30292] Re: indexを使用しない/ 使用する違いは?
Date: Mon, 30 Jun 2003 23:54:23 +0900
;;; [pgsql-jp: 30286]で書いたように、以下のようになったわけですが、
;;;
;;; ##########
;;; explain時のSQL文
;;; explain select * from haisyutu_map WHERE id_area = 80;
;;;
;;; 環境Aの結果
;;; Index Scan using haisyutu_map_pkey on haisyutu_map (cost=0.00..17.07
;;; rows=5 width=40)
;;; Index Cond: (id_area = 80)
;;;
;;; 環境Bの結果
;;; Seq Scan on haisyutu_map (cost=0.00..78.25 rows=353 width=40)
;;; ################3
予測結果行数 rows が異なるので、データの内容が異なるのではないでしょうか?
;;; 勝手に、indexを使用してくれた環境で、vacuumdb -a -f -z ではなく、
;;; psql 上で analyze をかけたところ、indexを使わなくなってしまいました。
;;;
;;; vacuumdb と analyze とでは、働きが違うのかな?とこれから調べるところです。
テーブルの概算タプル数を求める部分が異なります。VACUUM では、正確に求まりま
す。しかし、ANALYZE は、ゴミ領域の具合によっては、不正確になる事があります。
;;; index、パフォーマンス、プランナといった言葉で調べたところ、
;;;
;;; 以下のcreate文のようにprimary_keyを設定しただけでは、
;;; explain select * from haisyutu_map WHERE id_area = 80;といったSQLのとき
;;; にindexを使ってくれないのでは?という考えに至りました。
;;;
;;; create table haisyutu_map(
;;; id_area integer,
;;; id_material integer,
;;; img_total integer,
;;; 中略
;;; primary key(id_area, id_material)
;;; );
;;;
;;; そこで、create index aaaaa on haisyutu_map(id_area);として、
;;; 手動でindexを追加したところ、
;;; どちらの環境でも確実にindexを使用し、速度も格段に向上しました。
;;;
;;;
;;; indexを作成する際の指針として、
;;; 「SQL文のWHEREなどの条件に使用する列をindexにする」としました。
----------------------------------------------------------------
;;; indexを何パターンもつくることのデメリットを見つけられなかったので、今の
;;; ところこれで良いのか?と思うのですが、この考え方は正しいのでしょうか?
データが変更されるときにインデックスも変更されるので、インデックス数に応じて
その手間もかかります。
;;; たとえば、例に挙げてあるhaisyutu_mapというtableでは、
----------------------------------------------------------------
;;; 1:id_area で絞り込むので、作る。
(id_area, id_material) で作成していれば、以降の例のように、これは不要ではな
いでしょうか?
;;; 2:id_area と id_material 両方を条件に絞るので、primary_keyで作られる
;;; indexを使用
;;; 3:id_materialからしぼることは行わないので、
;;; create index bbbb opn haisyutu_map(id_material) は作っていません。
;;; といった具合なのですが。
ところで、データの順番を変えて試してみました。
create table haisyutu_map(
id_area integer,
id_material integer,
img_total integer,
primary key(id_area, id_material)
);
insert into haisyutu_map (n / 1000, n % 1000) -- n は 0〜100000 を順番に。
とした場合には、以下のようになりました。
explain select count(*) from haisyutu_map where id_area = 80;
QUERY PLAN
-------------------------------------------------------------------------------------------------
Aggregate (cost=1489.51..1489.51 rows=1 width=0)
-> Index Scan using haisyutu_map_pkey on haisyutu_map (cost=0.00..1487.07 rows=975 width=0)
Index Cond: (id_area = 80)
(3 rows)
explain analyze select count(*) from haisyutu_map where id_area = 80;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------------------------
Aggregate (cost=1489.51..1489.51 rows=1 width=0) (actual time=5.43..5.43 rows=1 loops=1)
-> Index Scan using haisyutu_map_pkey on haisyutu_map (cost=0.00..1487.07 rows=975 width=0) (actual time=0.25..4.38 rows=1000 loops=1)
Index Cond: (id_area = 80)
Total runtime: 5.95 msec
(4 rows)
Timing is on.
select count(*) from haisyutu_map where id_area = 80;
count
-------
1000
(1 row)
Time: 4.22 ms
set enable_indexscan to off;
SET
Time: 0.37 ms
select count(*) from haisyutu_map where id_area = 80;
count
-------
1000
(1 row)
Time: 141.26 ms
予測もインデックススキャンで、結果もインデックススキャンの方が速く、予測と結果が一致しています。
次に、
insert into haisyutu_map (n / 1000, n % 1000) -- n は 0〜100000 で、order by random()
とすると、
explain select count(*) from haisyutu_map where id_area = 80;
QUERY PLAN
-----------------------------------------------------------------------
Aggregate (cost=1743.39..1743.39 rows=1 width=0)
-> Seq Scan on haisyutu_map (cost=0.00..1741.00 rows=957 width=0)
Filter: (id_area = 80)
(3 rows)
Timing is on.
select count(*) from haisyutu_map where id_area = 80;
count
-------
1000
(1 row)
Time: 142.34 ms
PostgreSQL を停止し起動。
set enable_seqscan to off;
SET
Time: 0.43 ms
explain select count(*) from haisyutu_map where id_area = 80;
QUERY PLAN
-------------------------------------------------------------------------------------------------
Aggregate (cost=1959.41..1959.41 rows=1 width=0)
-> Index Scan using haisyutu_map_pkey on haisyutu_map (cost=0.00..1957.02 rows=957 width=0)
Index Cond: (id_area = 80)
(3 rows)
Time: 1.10 ms
select count(*) from haisyutu_map where id_area = 80;
count
-------
1000
(1 row)
Time: 56.01 ms
予測が外れました。
Kenji Sugita
pgsql-jp メーリングリストの案内