web-dev-qa-db-ja.com

3兆行を超えるPostgreSQLテーブルでのクエリの管理と高速化

10年以上にわたる時系列データがあり、3兆を超える行と10の列があります。

現時点では、128 GBのRAM=のPCIe SSDを使用していますが、クエリにかなりの時間がかかることがわかりました。たとえば、次のコマンドの実行には15分以上かかります。

_SELECT * FROM tbl WHERE column_a = 'value1' AND column_b = 'value2';
_

テーブルは主に読み取りに使用されます。テーブルに書き込まれるのは、約1,500万行を挿入する毎週の更新時のみです。

非常に大きなテーブルを管理する最良の方法は何ですか?年ごとに分割することをお勧めしますか?

テーブルサイズは542 GB、外部サイズは109 GBです。

EXPLAIN (BUFFERS, ANALYZE)出力:

_"Seq Scan on table  (cost=0.00..116820941.44 rows=758 width=92) (actual time=0.011..1100643.844 rows=667 loops=1)"
"  Filter: (("COLUMN_A" = 'Value1'::text) AND ("COLUMN_B" = 'Value2'::text))"
"  Rows Removed by Filter: 4121893840"
"  Buffers: shared hit=2 read=56640470 dirtied=476248 written=476216"
"Total runtime: 1100643.967 ms"
_

テーブルは次のコードを使用して作成されました:

_CREATE TABLE tbl (
  DATE     timestamp with time zone,
  COLUMN_A text,
  COLUMN_B text,
  VALUE_1  double precision,
  VALUE_2  double precision,
  VALUE_3  double precision,
  VALUE_4  double precision,
  VALUE_5  double precision,
  VALUE_6  double precision,
  VALUE_7  double precision,
);

CREATE INDEX ix_table_name_date ON table_name (DATE);
_
6
Greg

DATEの既存のインデックスは、クエリでは明らかに役に立ちません。クエリの最初の明白なステップ:

SELECT * FROM tbl WHERE column_a = 'value1' AND column_b = 'value2';

column_aまたはcolumn_b(どちらかより選択的である)のindex、または(column_a, column_b)の複数列インデックスである可能性があります。

CREATE INDEX tbl_a_b_idx ON tbl(column_a, column_b);

詳細:

次に、クエリからテーブルの大部分を安全に除外できる場合は、部分インデックスを検討します。または、テーブルを100パーティションのようなものに分割します。そして constraint exclusion を使用します。

「それを年ごとに分割する」ことは、あなたが考えたように、与えられたクエリのDATEのインデックスと同じくらい役に立たない(有害でさえある)でしょう。パーティションは、役立つために、クエリの述語(column_aおよびcolumn_b)の列に基づく必要があります。 one列だけの述語は、この点ではるかに簡単です。さまざまな列でフィルタリングする重要なクエリがある場合、パーティション化はおそらくうまくいきません。 (部分インデックスはまだ可能性があります。)

パーティショニングが適切でない場合は、新しいインデックスに基づいてデータをCLUSTERすることで、より侵襲性の低い対策を講じることができます(これには部分インデックスを使用できません)。または、クエリのソートされた出力から新しいテーブルを作成するだけです。テーブルはほとんど読み取り専用であるため、これは特に興味深いものです。これを行うには少なくとも1回支払う必要がありますが、そのときは非常にコストがかかります。テーブル全体をいずれかの方法で書き直す必要があります。 RAMできるだけ多くの空き領域が必要であり、テーブルの排他ロックが必要です。または、排他ロックを回避するには、pg_repackを使用します。

必ずPostgresの最新バージョンを実行してください。今後のPostgres 9.5BRINインデックス (ブロック範囲インデックス)。非常に大きなテーブルのインデックスサイズを大幅に削減できます。まさにあなたが探しているものかもしれません。

5