[pgsql-jp: 41925] 【質問】サブクエリを使った検索文の実行時間短縮について

toshio_uchiyama @ mirror.ocn.ne.jp toshio_uchiyama @ mirror.ocn.ne.jp
2017年 3月 29日 (水) 02:51:08 JST


Postgresql -jp の皆様。
 お世話になります。内山と申します。
 よろしくお願いします。

 PostgreSQL 9.4.4 とpg-bigm 1.1 を用いた
全文検索エンジンで、条件語

1. スポーツ と テニス の両方を含む
2. ありがとう と 感謝 の両方を含む

を変更しただけの同一検索文
(サブクエリを用いている)で実行時間に差が
でています。1 の条件語での検索が 1 秒程度で
2 の検索語での検索が11秒程度です。
どちらも 1 秒程度だと助かります。
 テーブルは、変な名前ですが manual という名前で
ビデオの字幕を登録したものです。

カラム	データ型
id	bigint
theme	text
video	text
starttime	numeric(10,3)
endtime	numeric(10,3)
content	text
track	bigint
userid	text
eng_conv	integer
time	timestamp without time zone

の10列です。theme がビデオ名です。video が
ビデオの id です。starttimeとendtime が字幕の
開始時間と終了時間です。content が字幕です。
track は字幕番号です。userid が登録者の
ユーザーID です。eng_conv は英会話動画の
フラグです。time が登録時刻です。複数の字幕に
同じ video ID とトラック番号がついています。
 インデックスは、

manual_pkey
CREATE UNIQUE INDEX manual_pkey ON manual USING btree (id)
manual_eng_conv_idx
CREATE INDEX manual_eng_conv_idx ON manual USING btree (eng_conv)
manual_lower_gin_content_idx
CREATE INDEX manual_lower_gin_content_idx ON manual USING gin
(lower(content) gin_bigm_ops)
manual_lower_gin_theme_idx
CREATE INDEX manual_lower_gin_theme_idx ON manual USING gin (lower(theme)
gin_bigm_ops)
manual_track_idx
CREATE INDEX manual_track_idx ON manual USING btree (track)
manual_video_idx
CREATE INDEX manual_video_idx ON manual USING btree (video)

の6つを付けています。

1 の検索語の場合の explain analyze が
moovle=# explain analyze select * from manual where lower( content ) like
lower( '%スポーツ%') and video in ( select distinct video from manual where
lower( content ) like lower( '%テニス%' ));

QUERY PLAN
----------------------------------------------------------------------------
----------------------------------------------------------------------------
--
Nested Loop  (cost=8749.96..8936.05 rows=1 width=185) (actual
time=4.825..202.034 rows=177 loops=1)
   ->  HashAggregate  (cost=8660.73..8660.76 rows=3 width=12) (actual
time=0.712..0.764 rows=193 loops=1)
         Group Key: manual_1.video
         ->  Bitmap Heap Scan on manual manual_1  (cost=52.50..8651.86
rows=3549 width=12) (actual time=0.131..0.615 rows=327 loops=1)
               Recheck Cond: (lower(content) ~~ '%テニス%'::text)
               Heap Blocks: exact=233
               ->  Bitmap Index Scan on manual_lower_gin_content_idx
(cost=0.00..51.62 rows=3549 width=0) (actual time=0.104..0.104 rows=327
loops=1)
                     Index Cond: (lower(content) ~~ '%テニス%'::text)
   ->  Bitmap Heap Scan on manual  (cost=89.23..91.74 rows=1 width=185)
(actual time=1.040..1.041 rows=1 loops=193)
         Recheck Cond: ((video = manual_1.video) AND (lower(content) ~~ '%ス
ポーツ%'::text))
         Heap Blocks: exact=113
         ->  BitmapAnd  (cost=89.23..89.23 rows=1 width=0) (actual
time=1.038..1.038 rows=0 loops=193)
               ->  Bitmap Index Scan on manual_video_idx  (cost=0.00..26.47
rows=1454 width=0) (actual time=0.119..0.119 rows=846 loops=193)
                     Index Cond: (video = manual_1.video)
               ->  Bitmap Index Scan on manual_lower_gin_content_idx
(cost=0.00..61.62 rows=3549 width=0) (actual time=0.913..0.913 rows=1606
loops=193)
                     Index Cond: (lower(content) ~~ '%スポーツ%'::text)
 Planning time: 0.305 ms
 Execution time: 202.111 ms
(18 行)

2 の検索語の explain analyze が
moovle=# explain analyze select content from manual where lower( content )
like lower( '%ありがとう%' ) and video in ( select video from manual where
lower( content ) like lower( '%感謝%' ));

QUERY PLAN
----------------------------------------------------------------------------
----------------------------------------------------------------------------
----
Nested Loop  (cost=8748.89..8952.81 rows=596 width=48) (actual time=69.371..
11769.517 rows=4321 loops=1)
   ->  HashAggregate  (cost=8650.73..8650.76 rows=3 width=12) (actual
time=20.822..21.578 rows=1904 loops=1)
         Group Key: manual_1.video
         ->  Bitmap Heap Scan on manual manual_1  (cost=42.50..8641.86
rows=3549 width=12) (actual time=4.855..16.387 rows=4541 loops=1)
               Recheck Cond: (lower(content) ~~ '%感謝%'::text)
               Heap Blocks: exact=3647
               ->  Bitmap Index Scan on manual_lower_gin_content_idx
(cost=0.00..41.62 rows=3549 width=0) (actual time=3.041..3.041 rows=4541
loops=1)
                     Index Cond: (lower(content) ~~ '%感謝%'::text)
   ->  Bitmap Heap Scan on manual  (cost=98.16..100.67 rows=1 width=60)
(actual time=6.165..6.168 rows=2 loops=1904)
         Recheck Cond: ((video = manual_1.video) AND (lower(content) ~~ '%あ
りがとう%'::text))
         Rows Removed by Index Recheck: 0
         Heap Blocks: exact=2986
         ->  BitmapAnd  (cost=98.16..98.16 rows=1 width=0) (actual
time=6.158..6.158 rows=0 loops=1904)
               ->  Bitmap Index Scan on manual_video_idx  (cost=0.00..25.40
rows=1454 width=0) (actual time=0.115..0.115 rows=797 loops=1904)
                     Index Cond: (video = manual_1.video)
               ->  Bitmap Index Scan on manual_lower_gin_content_idx
(cost=0.00..71.62 rows=3549 width=0) (actual time=6.005..6.005 rows=16570
loops=1904)
                     Index Cond: (lower(content) ~~ '%ありがとう%'::text)
 Planning time: 1.660 ms
 Execution time: 11769.988 ms
(19 行)

です。explain analyze で見たときの両者の違いは、
Rows Removed by Index Recheck: 0
です。これによって、実行時間にこんなに差が出るでしょうか。
 ご指導いただければ幸いです。
もし、recheck による差であろうという意見が
大半なら、recheck をしないですむ PGroonga を
試してみたいと思います。
 よろしくお願いします。



pgsql-jp メーリングリストの案内