2016-08-30 8 views
0

私は私の地元のPostgreSQL 9.5.3.0データベースへhttp://www.geonames.org/からすべてのテーブルをインポートし、そのようなインデックスとそれを浴びせ:PostgreSQLのgeonames DBにスロークエリのインデックスにもかかわらず

create extension pg_trgm; 
CREATE INDEX name_trgm_idx ON geoname USING GIN (name gin_trgm_ops); 
CREATE INDEX fcode_trgm_idx ON geoname USING GIN (fcode gin_trgm_ops); 
CREATE INDEX fclass_trgm_idx ON geoname USING GIN (fclass gin_trgm_ops); 
CREATE INDEX alternatename_trgm_idx ON alternatename USING GIN (alternatename gin_trgm_ops); 
CREATE INDEX isolanguage_trgm_idx ON alternatename USING GIN (isolanguage gin_trgm_ops); 
CREATE INDEX alt_geoname_id_idx ON alternatename (geonameid) 

そして今、私は国の名前を照会したいと思いますこのクエリは限り速いSSDとoctacoreマシン上で13〜15秒のようになりますけれども

残念ながら
select g.geonameid as geonameid ,a.alternatename as name,g.country as country, g.fcode as fcode 
from geoname g,alternatename a 
where 
     a.isolanguage=LOWER('de') 
     and a.alternatename ilike '%Sa%' 
     and (a.ishistoric = FALSE OR a.ishistoric IS NULL) 
     and (a.isshortname = TRUE OR a.isshortname IS NULL) 
     and a.geonameid = g.geonameid 
     and g.fclass='A' 
     and g.fcode ='PCLI'; 

:さまざまな言語や相互参照にgeonamesはそうのように、これらの代替名を持つ属性。私にはその何とかシーケンススキャンを示すように思わ

Nested Loop (cost=0.43..237138.04 rows=1 width=25) (actual time=1408.443..10878.115 rows=15 loops=1) 
    Output: g.geonameid, a.alternatename, g.country, g.fcode 
    -> Seq Scan on public.alternatename a (cost=0.00..233077.17 rows=481 width=18) (actual time=0.750..10862.089 rows=2179 loops=1) 
     Output: a.alternatenameid, a.geonameid, a.isolanguage, a.alternatename, a.ispreferredname, a.isshortname, a.iscolloquial, a.ishistoric 
     Filter: (((a.alternatename)::text ~~* '%Sa%'::text) AND ((a.isolanguage)::text = 'de'::text)) 
     Rows Removed by Filter: 10675099 
    -> Index Scan using pk_geonameid on public.geoname g (cost=0.43..8.43 rows=1 width=11) (actual time=0.006..0.006 rows=0 loops=2179) 
     Output: g.geonameid, g.name, g.asciiname, g.alternatenames, g.latitude, g.longitude, g.fclass, g.fcode, g.country, g.cc2, g.admin1, g.admin2, g.admin3, g.admin4, g.population, g.elevation, g.gtopo30, g.timezone, g.moddate 
     Index Cond: (g.geonameid = a.geonameid) 
     Filter: ((g.fclass = 'A'::bpchar) AND ((g.fcode)::text = 'PCLI'::text)) 
     Rows Removed by Filter: 1 

(私はかなり低いと考える)481行で実行されるが、それにもかかわらず、非常に長い時間がかかる:「詳細な分析説明すると、」これが表示されます。私は現在、これを理解できません。何か案は?

+0

Postgresが 'alternatename'の行の数を過小評価内容に応じたパラメータは、動的利用マルチカラムまたは濾過インデックスです。そして、明らかに 'alternatename.alternatename'のインデックスは使用されていません。統計を更新するために 'analyze alternatename'を実行しましたか? 'ishistoric'と' isshortname'の条件がテーブルから削除される行の数はいくつですか?たぶん助けてくれる組み合わせインデックスを作成した場合や、結果からさらに多くの行を削除するインデックスを作成した場合だけです。ブール値列のNULL値を取り除いて、 'または 'ヌル'が必要ない(適切にインデックスするのが難しい)場合は、おそらく役に立ちます。 –

+1

パフォーマンスとは関係ありません:古い、 'where'節で時代遅れで壊れやすい暗黙的な結合を使用し、明示的な' JOIN'演算子を使用します –

+0

結果なしでalternatenameを解析しました。方程式からishistoricとisshortnameを取り除くと、それは私に2秒のブーストを与えます。 – keyboardsamurai

答えて

2

トリグラムは、最低でも3文字ある場合にのみ動作し、%Sa%が検索されない場合は、%foo%となります。しかし、あなたのインデックスはまだ十分ではありません。他のテーブルの

CREATE INDEX jkb1 ON geoname(fclass, fcode, geonameid, country); 
CREATE INDEX jkb2 ON geoname(geonameid, country) WHERE fclass = 'A' AND fcode = 'PCLI'; 

同:

CREATE INDEX jkb3 ON alternatename(geonameid, alternatename) WHERE (a.ishistoric = FALSE OR a.ishistoric IS NULL) 
     AND (a.isshortname = TRUE OR a.isshortname IS NULL) AND isolanguage=LOWER('de') 
+1

もちろん、あなたは正しいです。選択時間は、パラメータ化されたインデックスを使用して25ms未満に、パラメータなしで120msに低下します。どうもありがとうございます。 – keyboardsamurai

関連する問題