pg_bigmは空文字検索が遅い?

%演算子での挙動

ここ数日、仕事外でpg_bigmと戯れていますが、そこでちょっと気になる事象が。

澤田さん作成の暫定版similarity()と%演算子を使っていて、空文字を条件値として与えるとちょっと遅いという事象に気づいた。
とりあえず、ipadicの辞書に対して % 演算子で類似するトークンを抜き出そうとしていたんだけど、

bigm=# EXPLAIN ANALYZE SELECT * FROM token2 WHERE token2 % 'あ';
                                                       QUERY PLAN                                                    
    
---------------------------------------------------------------------------------------------------------------------
----
 Bitmap Heap Scan on token2  (cost=21.30..549.55 rows=168 width=27) (actual time=1.720..19.381 rows=18 loops=1)
   Recheck Cond: (token2 % 'あ'::text)
   Rows Removed by Index Recheck: 7148
   ->  Bitmap Index Scan on token2_idx  (cost=0.00..21.26 rows=168 width=0) (actual time=1.521..1.521 rows=7166 loops
=1)
         Index Cond: (token2 % 'あ'::text)
 Total runtime: 19.416 ms
(6 rows)

条件値文字列が1文字でもあれば高速に処理してくれるけど、これが空文字になると

bigm=# EXPLAIN ANALYZE SELECT * FROM token2 WHERE token2 % '';
                                                           QUERY PLAN                                                
           
---------------------------------------------------------------------------------------------------------------------
-----------
 Bitmap Heap Scan on token2  (cost=45901.30..46429.55 rows=168 width=27) (actual time=315.382..315.382 rows=0 loops=1
)
   Recheck Cond: (token2 % ''::text)
   Rows Removed by Index Recheck: 167820
   ->  Bitmap Index Scan on token2_idx  (cost=0.00..45901.26 rows=168 width=0) (actual time=85.864..85.864 rows=16782
0 loops=1)
         Index Cond: (token2 % ''::text)
 Total runtime: 315.412 ms
(6 rows)

bigm=# 

costもactual timeもどーんと跳ね上がる。
"Rows Removed by Index Recheck: 167820" とあるから、IndexScanの後のRecheckで全件スキャンしちゃっているのだろうか・・・
例のRecheckを行わないGUCを設定すればここをスキップして高速化出来るのだろうけど・・・。

LIKEでの確認

これは % 演算子だけの問題なのかな?と思って一応、LIKE(~~演算子)でも試してみる。

bigm=# EXPLAIN ANALYZE SELECT * FROM token2 WHERE token1 ~~ '';
                                                           QUERY PLAN                                                
           
---------------------------------------------------------------------------------------------------------------------
-----------
 Bitmap Heap Scan on token2  (cost=1614200.01..1614204.02 rows=1 width=27) (actual time=101.819..101.819 rows=0 loops
=1)
   Recheck Cond: (token1 ~~ ''::text)
   Rows Removed by Index Recheck: 167820
   ->  Bitmap Index Scan on token1_idx  (cost=0.00..1614200.01 rows=1 width=0) (actual time=79.836..79.836 rows=16782
0 loops=1)
         Index Cond: (token1 ~~ ''::text)
 Total runtime: 101.850 ms
(6 rows)

bigm=# 

やっぱり同様ですねえ。

Recheckを無効化したら?

ということでRecheckを無効化して挙動を見てみる。

bigm=# SET pg_bigm.enable_recheck = off;
SET
bigm=# EXPLAIN ANALYZE SELECT * FROM token2 WHERE token1 ~~ '';
                                                           QUERY PLAN                                                
           
---------------------------------------------------------------------------------------------------------------------
-----------
 Bitmap Heap Scan on token2  (cost=1614200.01..1614204.02 rows=1 width=27) (actual time=79.697..95.707 rows=167820 lo
ops=1)
   Recheck Cond: (token1 ~~ ''::text)
   ->  Bitmap Index Scan on token1_idx  (cost=0.00..1614200.01 rows=1 width=0) (actual time=79.499..79.499 rows=16782
0 loops=1)
         Index Cond: (token1 ~~ ''::text)
 Total runtime: 102.899 ms
(5 rows)

bigm=# 

実行計画はちょっと変わった(Recheckをスキップした?)ようだけど、トータルとしてはcostもacutual timeもあまり変わらないなあ・・・
まあ、空文字を使って全文検索ということ自体、使用方法としては通常はありえないとは思うけど、ちょっと気になった。