30

PostgresデータベースのSELECTクエリの速度に関して問題があります。

キーとして2つの整数列を持つテーブルがあります:(int1、int2)このテーブルには約7000万行があります。

この環境で2種類の単純なSELECTクエリを作成する必要があります。

SELECT * FROM table WHERE int1=X;
SELECT * FROM table WHERE int2=X;

これらの2つの選択は、これらの7000万行のうちそれぞれ約10.000行を返します。これをできるだけ速く機能させるために、各列に1つずつ、合計2つのHASHインデックスを使用することを考えました。残念ながら、結果はそれほど良くありません。

                                                               QUERY PLAN                                                               
----------------------------------------------------------------------------------------------------------------------------------------
 Bitmap Heap Scan on lec_sim  (cost=232.21..25054.38 rows=6565 width=36) (actual time=14.759..23339.545 rows=7871 loops=1)
   Recheck Cond: (lec2_id = 11782)
   ->  Bitmap Index Scan on lec_sim_lec2_hash_ind  (cost=0.00..230.56 rows=6565 width=0) (actual time=13.495..13.495 rows=7871 loops=1)
         Index Cond: (lec2_id = 11782)
 Total runtime: 23342.534 ms
(5 rows)

これは、これらのクエリの1つのEXPLAINANALYZEの例です。約23秒かかります。私の期待は、この情報を1秒以内に取得することです。

これらはpostgresdbconfigのいくつかのパラメーターです。

work_mem = 128MB
shared_buffers = 2GB
maintenance_work_mem = 512MB
fsync = off
synchronous_commit = off
effective_cache_size = 4GB

どんな助け、コメントまたは考えでも本当にありがたいです。

前もって感謝します。

4

4 に答える 4

34

コメントを答えに抽出する:ここでのインデックス検索は非常に高速でした。すべての時間が実際の行の取得に費やされました。23秒/7871行=行あたり2.9ミリ秒。これは、ディスクサブシステム全体に分散しているデータを取得するのに適しています。シークは遅いです。a)データセットをRAMに収める、b)SSDを購入する、またはc)シークを最小限に抑えるために事前にデータを整理することができます。

PostgreSQL 9.2には、インデックスのみのスキャンと呼ばれる機能があり、テーブルにアクセスせずに(通常は)クエリに応答できます。btreeこれを、順序を自動的に維持するindexプロパティと組み合わせて、このクエリを高速化できます。int1、、int2および2つのフロートについて言及します。

CREATE INDEX sometable_int1_floats_key ON sometable (int1, float1, float2);
CREATE INDEX sometable_int2_floats_key ON sometable (int2, float1, float2);

SELECT float1,float2 FROM sometable WHERE int1=<value>; -- uses int1 index
SELECT float1,float2 FROM sometable WHERE int2=<value>; -- uses int2 index

また、これはディスクシークを魔法のように消去するのではなく、クエリ時間から挿入時間に移動するだけであることに注意してください。また、データを複製しているため、ストレージスペースも必要になります。それでも、これはおそらくあなたが望むトレードオフです。

于 2012-11-05T16:20:27.070 に答える
21

ウィルグリンありがとう。お気づきのように、問題はHDを介してシークし、インデックスを検索しないことでした。データセットをRAMにロードしたり、SSD HDを購入したりするなど、多くのソリューションを提案しました。しかし、データベース自体の外部で物事を管理することを含むこれら2つを忘れて、2つのアイデアを提案しました。

  1. データを再編成して、データのシークを減らします。
  2. PostgreSQL9.2の機能「インデックスのみのスキャン」を使用する

私はPostgreSQL9.1サーバーを使用しているため、オプション「1」を選択することにしました。

テーブルのコピーを作成しました。これで、同じデータを持つ同じテーブルが2回作成されました。それぞれにインデックスを作成しました。最初のインデックスは(int1)で、2番目のインデックスは(int2)で作成されました。次に、両方をそれぞれのインデックスでクラスター化しました(CLUSTERテーブルUSING ind_intX)。

これらのクラスター化されたテーブルの1つで行われた、同じクエリのEXPLAINANALYZEを投稿しています。

                                                         クエリプラン                                                            
-------------------------------------------------- -------------------------------------------------- -----------------------------------------  
lec_sim_lec2idでlec_sim_lec2id_indを使用したインデックススキャン(コスト=0.00..21626.82行=6604幅=36)(実際の時間=0.051..1.500行=8119ループ=1)
インデックス条件:(lec2_id = 12300)合計実行時間:
1.822ミリ秒(3行)

今、シークは本当に速いです。23秒から約2ミリ秒に短縮されました。これは印象的な改善です。この問題は私にとっては解決されたと思います。同じ問題を経験している他の人にも役立つことを願っています。

どうもありがとうございます。

于 2012-11-06T13:26:58.243 に答える
3

3300万行のテーブルと24億行のサイズの子テーブルの間で、単純な1対多の結合(PG v9.1)が実行される非常に遅いクエリのケースがありました。子テーブルの外部キーインデックスに対してCLUSTERを実行しましたが、最も単純なクエリであっても、クエリのタイムアウトに関する問題が解決されないことがわかりました。ANALYZEを実行しても問題は解決しませんでした。

大きな違いを生んだのは、親テーブルと子テーブルの両方で手動VACUUMを実行することでした。親テーブルがVACUUMプロセスを完了しているときでも、10分のタイムアウトから1秒で結果が返されるようになりました。

私がこれから取り除いているのは、v9.1の場合でも、通常のVACUUM操作が依然として重要であるということです。私がこれを行った理由は、オートバキュームが少なくとも2週間、どちらのテーブルでも実行されておらず、それ以降、多くのアップサートとインサートが発生していることに気付いたためです。今後、この問題に対処するために自動真空トリガーを改善する必要があるかもしれませんが、すべてがクリーンアップされた場合、数十億行の640GBテーブルはうまく機能すると言えます。良いパフォーマンスを得るために、まだテーブルを分割する必要はありません。

于 2014-02-21T16:53:08.907 に答える
0

非常にシンプルで効果的なワンライナーの場合、postgresマシンに高速のソリッドステートストレージがある場合は、次の設定を試してください。

random_page_cost=1.0

あなたの中であなたのpostgresql.conf

デフォルトはrandom_page_cost=4.0で、これは古い回転ディスクのようにシーク時間が長いストレージ用に最適化されています。これにより、シークのコスト計算が変更され、メモリへの依存度が低くなります(いずれにせよ最終的にスワップする可能性があります)

この設定だけで、数百万レコードの長いテーブルでのフィルタリングクエリが8秒から2秒に改善されました。

他の大きな改善は、私のテーブルのすべてのブール列でインデックスを作成することからもたらされました。これにより、2秒のクエリが約1秒に短縮されました。@willglynnの答えを確認してください。

お役に立てれば!

于 2018-03-27T17:13:31.147 に答える