1

残念ながら、実稼働環境 (90 列のテーブルに 300 万レコード) でクエリ (2 つの条件での選択/結合) を約 2 分で実行する大きな PostgreSQL プロジェクトに取り組んでいます。

クエリを最適化するものがないと仮定すると、クエリを高速化するために変更できる設定はありますか? これはデータベースの構成であり、何が自分のニーズに合うかわかりません。

version PostgreSQL 8.4.4 on i686-pc-linux-gnu, compiled by GCC gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44), 32-bit
checkpoint_completion_target    0.9
checkpoint_segments 10
custom_variable_classes pg_stat_statements
effective_cache_size    1GB
lc_collate  fr_FR.UTF-8
lc_ctype    fr_FR.UTF-8
listen_addresses    *
log_autovacuum_min_duration 0
log_line_prefix %t [%p]: [%l-1] user=%u,db=%d
log_min_duration_statement  30s
logging_collector   on
maintenance_work_mem    128MB
max_connections 100
max_stack_depth 2MB
pg_stat_statements.max  1000
pg_stat_statements.save on
pg_stat_statements.track    all
random_page_cost    1.5
server_encoding UTF8
shared_buffers  128MB
TimeZone    Europe/Paris
track_functions pl
wal_buffers 1MB
work_mem    8MB

クエリ:

SELECT distinct
    ((Table_Commande_Historique.COD_STECIAL
    || ',' || Table_Commande_Historique.COD_MCIAL
    || ',' || Table_Commande_Historique.NUM_REC_CLI
    || ',' || Table_Commande_Historique.NUM_DNT_CLI
    || ',' || Table_Commande_Historique.NUM_DDE)) cle
FROM G1DDE2_DDE Table_Commande_Historique
inner join "K2VER2_VER" ver
  on ( Table_Commande_Historique.NUM_REC_CLI
         = (string_to_array(ver.num_cle,','))[3]::int
    OR Table_Commande_Historique.NUM_DNT_CLI
         = (string_to_array(ver.num_cle,','))[3]::int
    OR ver.num_cle = (Table_Commande_Historique.COD_MCIAL
                     || ',' || Table_Commande_Historique.NUM_REC_CLI)
    OR ver.num_cle = (Table_Commande_Historique.COD_MCIAL
                     || ',' || Table_Commande_Historique.NUM_DNT_CLI) );

索引:

CREATE INDEX idx_combo1
  ON g1dde2_dde
  USING btree
  (((cod_mcial || ','::text) || num_rec_cli) );

  CREATE INDEX idx_combo2
  ON g1dde2_dde
  USING btree
  (((cod_mcial || ','::text) || num_dnt_cli) );

  CREATE INDEX idx_dnt
  ON g1dde2_dde
  USING btree
  (num_dnt_cli );

  CREATE INDEX idx_rec
  ON g1dde2_dde
  USING btree
  (num_rec_cli );

  CREATE INDEX idx_k2ver3sb
  ON "K2VER2_VER"
  USING btree
  (num_cle );

説明:

"HashAggregate  (cost=197.97..201.77 rows=69 width=29)"
"  ->  Nested Loop  (cost=1.29..197.35 rows=248 width=29)"
"        ->  Seq Scan on "K2VER2_VER" ver  (cost=0.00..2.58 rows=58 width=19)"
"        ->  Bitmap Heap Scan on g1dde2_dde table_commande_historique  (cost=1.29..2.84 rows=5 width=29)"
"              Recheck Cond: ((table_commande_historique.num_rec_cli = ((string_to_array((ver.num_cle)::text, ','::text))[3])::integer) OR (table_commande_historique.num_dnt_cli = ((string_to_array((ver.num_cle)::text, ','::text))[3])::integer) OR ((ver.num_cle)::text = (((table_commande_historique.cod_mcial)::text || ','::text) || (table_commande_historique.num_rec_cli)::text)) OR ((ver.num_cle)::text = (((table_commande_historique.cod_mcial)::text || ','::text) || (table_commande_historique.num_dnt_cli)::text)))"
"              ->  BitmapOr  (cost=1.29..1.29 rows=5 width=0)"
"                    ->  Bitmap Index Scan on idx_rec  (cost=0.00..0.32 rows=2 width=0)"
"                          Index Cond: (table_commande_historique.num_rec_cli = ((string_to_array((ver.num_cle)::text, ','::text))[3])::integer)"
"                    ->  Bitmap Index Scan on idx_dnt  (cost=0.00..0.32 rows=1 width=0)"
"                          Index Cond: (table_commande_historique.num_dnt_cli = ((string_to_array((ver.num_cle)::text, ','::text))[3])::integer)"
"                    ->  Bitmap Index Scan on idx_combo1  (cost=0.00..0.32 rows=1 width=0)"
"                          Index Cond: ((ver.num_cle)::text = (((table_commande_historique.cod_mcial)::text || ','::text) || (table_commande_historique.num_rec_cli)::text))"
"                    ->  Bitmap Index Scan on idx_combo2  (cost=0.00..0.32 rows=1 width=0)"
"                          Index Cond: ((ver.num_cle)::text = (((table_commande_historique.cod_mcial)::text || ','::text) || (table_commande_historique.num_dnt_cli)::text))"
4

1 に答える 1

3
version PostgreSQL 8.4.4

それは問題だ。これを読んで、マイナー リリースを検討し、セキュリティの脆弱性とバグの修正を入手してください。

http://www.postgresql.org/support/versioning/

これらには、パフォーマンスの問題を引き起こすバグが含まれることがあります。どのような修正が得られるかを確認するには、次の 8.4.5 から 8.4.11 へのメモを参照してください。

http://www.postgresql.org/docs/8.4/static/release.html

RAM ベースの設定の中にはおそらく低すぎるものもありますが、システムに搭載されている RAM の量や、他に何が実行されているかを知らなければ、特定の数値を提案する方法はありません。

shared_buffers  128MB

Linux 上の専用データベース サーバーに対する通常のアドバイスは、これをシステムの合計 RAM の 25% に設定し、最大で 8 GB に設定し、そこからベンチマークに基づいて調整することです。

effective_cache_size    1GB

これは RAM を割り当てませんが、プランナーは、同じクエリでの以前の読み取りからキャッシュ内に残っている可能性の推定に基づいて、ファイルからの繰り返し読み取りのコストを計算できます。OS がキャッシュとして表示するサイズに shared_buffers のサイズを追加することをお勧めします。

work_mem    8MB

これはトリッキーです。これは、さまざまな方法でクエリのパフォーマンスを向上させることができますが、値が大きいとキャッシュから追い出され、ディスク アクセスが増加する傾向があります。また、各クエリがこの量のスペースを (さまざまなクエリ ステップに対して) 数回割り当てることができることを考慮する必要があるため、通常は、許可された接続ごとにこのサイズの割り当てを 1 回許可する必要があります。これは、接続プールを使用して多数のユーザーを限られた数の実際のデータベース接続に集中させることが有益である理由の1 つです。より大きなサイズに余裕がある場合は、ビットマップ インデックス スキャンが「不可逆的」になり、インデックスの状態を再チェックする必要がなくなる可能性があるため、このクエリに役立つ可能性が非常に高くなります。

を設定しませんcpu_tuple_costが、デフォルト設定は通常、全体的に最適なプランを提供するには低すぎることがわかりました。大きなテーブルに 90 列あるとすると、これを 0.01 から 0.05 に増やすことをお勧めします。

を設定しませんeffective_io_concurrencyが、それが役立つ場合があります。さまざまな値でテストします。(もちろん、テストを実行して代替のパフォーマンスを比較する場合は、キャッシュの問題に注意してください。)

maintenance_work_mem    128MB

RAM の容量によっては、これが適切な場合とそうでない場合があります。当面の問題には影響しませんが、値を大きくすると自動バキュームがより効率的に実行され、インデックスの構築がより速く実行されるようになる可能性があります。

これらはおそらく少し低いです:

checkpoint_segments 10
wal_buffers 1MB

それらは差し迫った問題の一部ではありませんが、時々余分なディスク書き込みを引き起こす可能性があるため、おそらくそれらを調整するのに費用がかかります. wal_buffersマシンの RAM が非常に限られている場合を除き、通常は 32MB にする必要があります。 checkpoint_segments詳細を知らずに推定するのは困難ですが、ログと統計を確認してチェックポイントが頻繁に発生していることが判明した場合は、チェックポイントが発生するまでこれを増やしてくださいcheckpoint_timeout

于 2012-04-13T16:19:53.193 に答える