From okazaki @ focus-s.com Thu May 21 14:19:51 2009 From: okazaki @ focus-s.com (jiro okazaki) Date: Thu, 21 May 2009 14:19:51 +0900 Subject: [Ludia-users 236] =?iso-2022-jp?b?GyRCQmdOTCROPnI3byRHJS8lKCVqJHI5VCQmJEglNyE8GyhC?= =?iso-2022-jp?b?GyRCJTElcyU3JWMlayU5JS0lYyVzJEskSiRqISIkKiQ9JC8kSiRDGyhC?= =?iso-2022-jp?b?GyRCJEYkNyReJCYbKEI=?= Message-ID: <4A14E477.5030806@focus-s.com> Focus systemsの岡崎と申します。 ludiaを使って全文検索システムを構築しています。 ludiaで大量の条件を使ってクエリした場合にシーケンシャルスキャンにかわっ てしまい、処理時間がインデックス利用時より大幅にかかる、という現象が発生 しました。 原因を突き止めるため、最小構成を以下のように作り原因を追いかけました。 -- テスト用スキーマ create table item ( id serial primary key, name text not null ); create table prop ( id serial primary key, value text not null, source integer references item (id) on delete cascade ); create index prop_value_ft_idx on prop using fulltextu (value); -- ここまで ludia.sen_index_flagsは16です。 itemとpropはitem.idとprop.sourceで1:Nで関連を持っています。 propに大量のデータがはいっており(70万行、valueにASCIIで1024文字ずつの データが入っています)、次のようなクエリを投げています。 select * form item where id in (select source from prop where value %% '0' or value %% '1' or ...); そして実行計画を調べてみると条件件数が少ない間は以下のようにインデック スベースで実行されます。 Hash IN Join (cost=45078.64..63462.26 rows=7662 width=9) Hash Cond: (i.id = prop.source) -> Seq Scan on item i (cost=0.00..10432.00 rows=700000 width=9) -> Hash (cost=44982.87..44982.87 rows=7662 width=4) -> Bitmap Heap Scan on prop (cost=128.29..44982.87 rows=7662 width=4) Recheck Cond: ((value %% '0'::text) OR (value %% '1'::text) OR ... -> BitmapOr (cost=128.29..128.29 rows=7700 width=0) -> Bitmap Index Scan on prop_value_ft_index (cost=0.00..9.75 rows=700 width=0) Index Cond: (value %% '0'::text) -> Bitmap Index Scan on prop_value_ft_index (cost=0.00..9.75 rows=700 width=0) Index Cond: (value %% '1'::text) ... しかし、件数が多くなるとシーケンシャルスキャンに変わって処理されてしまい ます。 Hash IN Join (cost=175287535.89..175310271.60 rows=442871 width=9) Hash Cond: (i.id = prop.source) -> Seq Scan on item i (cost=0.00..10432.00 rows=700000 width=9) -> Hash (cost=175282000.00..175282000.00 rows=442871 width=4) -> Seq Scan on prop (cost=0.00..175282000.00 rows=442871 width=4) Filter: ((value %% '0'::text) OR (value %% '1'::text) OR ... 実際にそのほうが早いのであれば問題ないのですが、シーケンシャルスキャンに なった場合、段違いに実行時間がかかってしまいます。 explainで調べたところ、989件以下であればインデックススキャンを、990件以 上であればシーケンシャルスキャンになるようでしたので、検索条件を988件、 989件、990件でそれぞれexplain analyzeして時間を計測してみたところ、 988件: 152309.244 ms 989件: 183351.101 ms 990件: 977404.325 ms(!!) となりました。 実際の実行にかかるコストの違いは明らかで、インデックススキャンでは検索条 件の数だけpgs2*scan()関数が呼ばれるのに対して、シーケンシャルスキャンで はpgs2contain0が条件数*テーブルの全行数分だけかかります。 ソースを追いかけたところ、Bitmap heap scanのコスト推定で下位層の selectivityの値の合計を使っており、そのためフェッチにかかるコストを計算 しているため、シーケンシャルスキャンしたほうが早い、とプランナに評価され ていたようです。 現在のludiaではcontsel関数を使ってselectivityを計算しており、その値は 0.001。つまり0.1%が帰ってくると推定されます。そのため条件が増えていき、 たとえば条件数が1000に近づけばコスト的にはどうやってもシーケンシャルス キャンの方が早いと推定されることになります。 結局のところ、bitmap heap scan on propでのデータベースページのフェッチコ ストが支配的なのが原因でした。 本当は適正値を求めるように選択性評価関数をちゃんと用意するべきなんでしょ うが、まだsennaの中身まではちゃんと追いかけられていないので急場をしのぐ ためにselectivityを下げることで逃げを打つことにしました。 逃げをうったコードのパッチを作りましたので添付しておきます。 パッチを当てるとパラメータのludia.selectivityとludia.join_selectivityを 参照するようになります。 ludia.selectivityで制約選択性予測関数で返す値を、ludia.join_selectivity で結合選択性予測関数で返す値を実数で設定できるようにしました。 デフォルト値はそれぞれもとの予測関数の値と同じ0.001にしています。 以上です。 -- 株式会社 フォーカスシステムズ okazaki @ focus-s.com 岡崎 次朗 (おかざき じろう) -------------- next part -------------- テキスト形式以外の添付ファイルを保管しました... ファイル名: selectivity.patch 型: text/x-patch サイズ: 7685 バイト 説明: 無し URL: http://lists.sourceforge.jp/mailman/archives/ludia-users/attachments/20090521/c17c47c0/attachment.bin From ikari-ml @ ecoin.jp Fri May 22 17:02:28 2009 From: ikari-ml @ ecoin.jp (ikari-ml @ ecoin.jp) Date: Fri, 22 May 2009 17:02:28 +0900 Subject: [Ludia-users 237] =?iso-2022-jp?b?GyRCOCE6dyQsJEckLSReJDskcxsoQg==?= Message-ID: <20090522163725.1BF4.A0FB120E@ecoin.jp> 碇と申します 環境 ludia 1.5.2 senna 1.1.4 ubuntu 9.0.4 postgres 8.3.7 senna configureオプション --with-mecab=no --prefix=/usr #動作しない為、とりあえずmecabをはずしてみました #mecabがあっても動作していません ludia configure オプション なし postgres 8.3系でコンパイルが通らないため http://decide.cocolog-nifty.com/blog/2009/03/postgresql-836-.html こちらを参考に pgsenna.cの612行目を reltuples = IndexBuildHeapScan(heap, index, indexInfo, true, buildCallback, (void *) &bs); 変更してコンパイル postgresql.confにて log_min_messages = debug1 create database test with encoding = 'utf-8'; psql -f /usr/share/postgresql/8.3/main/pgsenna2.sql test create table t2 (col1 text,col2 int); create index idx1 on t1 using fulltextb(col1); insert into t2 values ('すもももももももものうち',1); insert into t2 values ('ももから生まれた桃太郎', 2); この状況で select * from t2 where col1 @@ 'もも'; で検索にヒットしません explain select * from t2 where col1 @@ 'もも'; すると Seq Scan on t2 (cost=0.00..1.07 rows=1 width=36) Filter: (col1 @@ 'もも'::text) となります ノード番号を調べて16485とでたので、その名前のファイルの大きさを見ると0で す stringsをかけてみたところ 16485.SEN SENNA:IO:01.000 SENNA:SYM:01.00 16485.SEN.i SENNA:IO:01.000 SENNA:INV:01.00 16485.i.c SENNA:IO:01.000 16485.l SENNA:IO:01.000 SENNA:SYM:01.00 どのあたりをチェックすればいいでしょうか? 以上よろしくお願いします -- 碇 永志 From okazaki @ focus-s.com Fri May 22 18:16:46 2009 From: okazaki @ focus-s.com (jiro okazaki) Date: Fri, 22 May 2009 18:16:46 +0900 Subject: [Ludia-users 238] Re: =?iso-2022-jp?b?GyRCOCE6dyQsJEckLSReJDskcxsoQg==?= In-Reply-To: <20090522163725.1BF4.A0FB120E@ecoin.jp> References: <20090522163725.1BF4.A0FB120E@ecoin.jp> Message-ID: <4A166D7E.70704@focus-s.com> 岡崎です。 ikari-ml @ ecoin.jp さんは書きました: > 碇と申します > > 環境 > ludia 1.5.2 > senna 1.1.4 > > ubuntu 9.0.4 > postgres 8.3.7 > > PostgreSQL のバージョンか8.3.7と言うのはまちがいないですね? PostgreSQL 8.3以降から以前にcontribにあったtsearchと呼ばれる検索用イン デックスが本家に取り込まれたため、演算子 '@@' はそちらが利用するように なってしまいました。 そのためLudiaでは8.3以降のPostgreSQLにインストールする場合には演算子 '%%' を使うように変更されています。 ですから > この状況で > select * from t2 where col1 @@ 'もも'; > で検索にヒットしません > のクエリを select * from t2 where col1 %% 'もも'; としてやれば結果がちゃんと帰るはずです。 -- 株式会社 フォーカスシステムズ okazaki @ focus-s.com 岡崎 次朗 (おかざき じろう) From ikari-ml @ ecoin.jp Fri May 22 18:37:09 2009 From: ikari-ml @ ecoin.jp (ikari-ml @ ecoin.jp) Date: Fri, 22 May 2009 18:37:09 +0900 Subject: [Ludia-users 239] Re: =?iso-2022-jp?b?GyRCOCE6dyQsJEckLSReJDskcxsoQg==?= In-Reply-To: <4A166D7E.70704@focus-s.com> References: <20090522163725.1BF4.A0FB120E@ecoin.jp> <4A166D7E.70704@focus-s.com> Message-ID: <20090522183529.1BF7.A0FB120E@ecoin.jp> 碇です はいPostgreSQLは8.3.7です 確かに%%を使ったところ検索できました ありがとうございました On Fri, 22 May 2009 18:16:46 +0900 jiro okazaki 様wrote: > 岡崎です。 > > ikari-ml @ ecoin.jp さんは書きました: > > 碇と申します > > > > 環境 > > ludia 1.5.2 > > senna 1.1.4 > > > > ubuntu 9.0.4 > > postgres 8.3.7 > > > > > PostgreSQL のバージョンか8.3.7と言うのはまちがいないですね? > PostgreSQL 8.3以降から以前にcontribにあったtsearchと呼ばれる検索用イン > デックスが本家に取り込まれたため、演算子 '@@' はそちらが利用するように > なってしまいました。 > > そのためLudiaでは8.3以降のPostgreSQLにインストールする場合には演算子 > '%%' を使うように変更されています。 > ですから > > > この状況で > > select * from t2 where col1 @@ 'もも'; > > で検索にヒットしません > > > のクエリを > > select * from t2 where col1 %% 'もも'; > > としてやれば結果がちゃんと帰るはずです。 > > -- > 株式会社 フォーカスシステムズ > okazaki @ focus-s.com > 岡崎 次朗 (おかざき じろう) > > _______________________________________________ > Ludia-users mailing list > Ludia-users @ lists.sourceforge.jp > http://lists.sourceforge.jp/mailman/listinfo/ludia-users -- 碇 永志