2016-06-22 1 views
0

他の2つのテーブルからテーブルを作成しようとしています。私のコードは動作しますが、実際には遅いです(gnameレコードにつき20msなので、完了には3 +日かかるでしょう)。postgresqlの最適化(高速化)11MioレコードのLOOPが25k行と一致するようにする

基本的に私は11mioポイントと25kグリッドを持っており、グリッドをそれぞれのポイントにリンクするテーブルを生成したいと考えています。私は、次の後に1つのgnameレコードを実行し、その半径内のいずれかのグリッドの中心点がST_DWithinであるかどうかを確認します。もし私がその情報を保存したいならば。

  • gnamesテーブルは11Mioレコードを有し、各レコードは、複数のグリッド(MAX4)であることができる
  • グリッドテーブルは、私は数を設定する(サイクルを用いて、以下の機能を書いた25Kレコード

を有しますループ)とlpoffset(特定のポイントから開始します)、DBは、それだけで一日、何のために実行させることがDBに書き込まれたときにクラッシュしたので(ループが完了一度だけ、それが書かれているようだ?)

CREATE OR REPLACE FUNCTION gnames_to_grid(cycles integer, lpoffset integer) 
    RETURNS integer AS 

$BODY$ 
DECLARE 
    r RECORD; 
    index integer:=lpoffset; 

BEGIN 
    RAISE NOTICE 'start'; 

    FOR r IN 
     SELECT gnameid, the_gm FROM gname LIMIT cycles OFFSET lpoffset 
    LOOP 

     EXECUTE 'INSERT INTO gname_grid 
     SELECT ' || r.gnameid || ', grid.id FROM grid 
     WHERE ST_DWithin(' || quote_literal(r.the_gm::character varying) || ',the_gm,100000,true) '; 

     index = index +1; 
     --count number of records written to table 
     RAISE NOTICE 'after: %', quote_literal(index); 
    END LOOP; 
    -- return next offset 
    RAISE NOTICE 'end'; 

    RETURN index; 
END 
$BODY$ 
    LANGUAGE plpgsql VOLATILE 

私は15%のCPUと30%のRAMを使います。私はDBの値をより多く使うように設定しましたが、使用や速度の変更はありません。 lpoffsetのために、私は同時に2回機能を実行させてからCPUを30%にすることができますが、もっと良い解決策があるはずです。誰かが私にこれを改善する方法を教えることができたら、とても嬉しく思っています。

おかげ

EDIT: "wildpassers"

からの質問に答えるために、あなたは地理フィールドにインデックスを持っていますか?
GNは(座標列上の)インデックスが
grが、彼らは箱を(座標列上の)インデックス
https://github.com/colemanm/gazetteer/blob/master/docs/geonames_postgis_import.mdから学んだ)

をバウンディングしているかしていましたか?
I私は関数を使用して自動的にやったのに - 下のリンクの下に最初のノートを参照してください
ST_DWithin function

有効な統計情報がありますか?
ここではどういう意味ですか?

クエリプランは何ですか? LOOPのため

- それは関数と呼ばれているとして、それはすべての詳細を表示していないようだ(それはまた、1000行で実行された)、または単に

"Result (cost=0.00..0.26 rows=1 width=0) (actual time=26714.823..26714.823 rows=1 loops=1)" 
"Planning time: 0.017 ms" 
"Execution time: 26714.836 ms" 
を「説明」よりも、他のいくつかの方法があります登録しよう

"Insert on geoname_grid_2 (cost=0.00..1597498489.76 rows=1000 width=8) (actual time=28343.040..28343.040 rows=0 loops=1)" 
" -> Limit (cost=0.00..1597498479.76 rows=1000 width=8) (actual time=52.782..28319.443 rows=1000 loops=1)" 
"  -> Nested Loop (cost=0.00..150564231717.67 rows=94250 width=8) (actual time=52.781..28319.214 rows=1000 loops=1)" 
"    Join Filter: (((gn.the_geom)::geography && st_expand((gr.the_geom)::geography, '100000'::double precision)) AND ((gr.the_geom)::geography && st_expand((gn.the_geom)::geography, '100000'::double precision)) AND _st_dwithin((gn.the_geom)::geo (...)" 
"    Rows Removed by Join Filter: 15969526" 
"    -> Seq Scan on geoname gn (cost=0.00..590016.50 rows=11064750 width=36) (actual time=0.004..0.545 rows=625 loops=1)" 
"    -> Materialize (cost=0.00..816.31 rows=25554 width=36) (actual time=0.000..1.150 rows=25553 loops=625)" 
"     -> Seq Scan on grid gr (cost=0.00..688.54 rows=25554 width=36) (actual time=0.233..5.001 rows=25554 loops=1)" 
"Planning time: 0.202 ms" 
"Trigger for constraint geoname_grid_2_geoname_geonameid_fkey: time=129.146 calls=1000" 
"Trigger for constraint geoname_grid_2_grid_id_fkey: time=78.144 calls=1000" 
"Execution time: 28551.360 ms" 

サーバー・チューニングのための


サーバはIntelCore I7、12ギガバイトRAM、Winows 10 OSのチューニングのための

(私はここでの主なポイントを全体のファイルを添付するための方法を見つけることができませんでした)何か他のものが有用であろうなら、私が知っている-LEtです:

max_connections = 20 
shared_buffers = 512MB 
effective_cache_size = 9GB 
work_mem = 100488kB 
maintenance_work_mem = 1536MB 
min_wal_size = 4GB 
max_wal_size = 8GB 
checkpoint_completion_target = 0.9 
wal_buffers = 16MB 
default_statistics_target = 500 

おかげ

+1

ループやダイナミックSQLは必要ありません(テーブル名やカラム名のどれも可変ではありません)プレーンSQLに書き直すことができます。 (ただし、LIMITとOFFSETが干渉する可能性があります) – wildplasser

+0

私はwildplasserに同意します:ループや動的SQL(または関数)を必要としません –

答えて

0

[OK]をもう一度テストして、テーブル全体を再作成してもう一度コードを実行してください。今は3時間から30分になりました。私は今、何らかの理由で、たとえ同じ方法で作成されたとしても、インデックスが最初のテーブルで壊れていたと信じています。

私にとってのレッスン:何か問題がなければ、削除して再作成し、問題が解決しないかどうかを確認してください。

0

[Iは、テーブル定義を持っていないので、以下のコードが不完全になり]:

INSERT INTO gname_grid (xxxx,yyyy) 
SELECT gn.gnameid, gr.id 
FROM gname gn 
JOIN grid gr ON ST_DWithin(gn.the_gm, gr.the_gm, 100000, true) 
    ; 
追加

制限とオフセットには余分な作業が必要になります...

+0

ありがとうございます。あなたの提案はうまくいきますが、時間はちょっと遅くてもまったく同じです。他の提案はありますか? – TheRealPir

+0

遅いことは非常に確かではありません...ジオフィールドにインデックスがありますか?彼らはバウンディングボックスを持っていますか?有効な統計はありますか?クエリプランは何ですか?サーバー調整? – wildplasser

+0

上記の説明はオリジナルのテキストに追加されました – TheRealPir

関連する問題