これらの数値とクエリの必要条件を使用して、データベースのパフォーマンスを最適化しようとしています。
これらの必要条件により、このソリューションに到達しました(強い欠点、以下で説明)。
[A] TABLE main_segments_history(
id_segment integer NOT NULL,
day date NOT NULL,
day_slices bigint[],
CONSTRAINT main_segments_history_pk PRIMARY KEY (id_segment,day)
)
[B] TABLE current_segment_release_state(
id_segment integer NOT NULL,
release_date timestamptz,
... all other attributes ...
CONSTRAINT currsegm_release_state_pk PRIMARY KEY (id_segment,release_date)
)
[A]テーブルの説明:
pg_partman
)。各パーティションは1か月です[B]テーブルの説明:
ネットワークを詳しく説明するバックエンドプロセスがあります。
3分ごとに、各セグメントの状態を挿入または更新します。
つまり、このプロセスでは、1日の開始時に新しい行が挿入され、3分ごとに内部配列が更新されます。
このソリューションのadvantages:
欠点:
constraint_exclusion。日付範囲でクエリを実行する場合、PostgreSQLのその機能/パラメータを使用する必要があります。これは、複数のパーティションにまたがるプリコンパイル済みクエリで定数値を使用しています。例:
制約除外はOK(2017年2月と3月にのみ検索されます):
SELECT * FROM main_segments_history
WHERE day BETWEEN '2017-01-01' AND '2017-02-03'
制約除外KO(すべてのパーティションテーブルを検索します):
SELECT * FROM main_segments_history m
JOIN sometable s ON s.id=m.id_segment
WHERE day BETWEEN s.day_from AND s.day_to
アップデートはevilです。
パフォーマンスの問題のために自動バキュームをオフにし、毎晩バッチで実行しました。
このように毎日約90Mから190Mの更新があることを考慮してください。これは、postgreSQLによって完全に書き換えられた行の数でもあります(UPDATEが削除された行にフラグを付け、新しい行が挿入)毎日。
さらに、UPDATEは非常に時間のかかる操作であり、書き込みの遅延を引き起こすことがよくあります。
最初に、LINK-TO-DATAデザインを使用する可能性について調査します。たとえば、セグメントIDのコンテナーとしてテーブルを使用し、セグメント状態のBIG TABLEにdata_idを使用しますが、それぞれの行数を数えるだけで破棄しました処理する月:〜2.880.000.0は、1日あたり最大3GBの容量です。あまりよくない。
についてどう思いますか?このシステムを最適化するためのソリューションはありますか?
テーブルへの更新を回避する唯一の方法は、しないだけですそれら。データをログに記録しているだけなので、1日分のデータを保存する日次テーブルをお勧めします。 1日に1億9000万回の更新を行う代わりに、1日に1億9000万回の挿入を行うことができます。セグメントの数と同じ数の更新。
CREATE TABLE main_segments_history
(
id_segment integer NOT NULL,
day date NOT NULL,
day_slices bigint[],
CONSTRAINT main_segments_history_pk PRIMARY KEY (id_segment, day)
) ;
CREATE TABLE dayly_segments
(
id_segment integer NOT NULL,
day date NOT NULL,
id_slice integer NOT NULL,
slice bigint,
PRIMARY KEY (id_segment, day, id_slice)
) ;
これは、1日のデータをシミュレートします(そして200セグメント。
INSERT INTO
dayly_segments
(id_segment, day, id_slice, slice)
SELECT
id_segment, '2017-01-01', id_slice, (random()*1e7)::bigint
FROM
generate_series (1, 200) AS s1(id_segment)
CROSS JOIN generate_series (1, 20*24) AS s2(id_slice) ;
vacuuming
プロセスを実行するときに、アクティビティが少ない時間があると思います。その時点で、dayly_segments
テーブルからmain_segments_history
にデータを移動し、すべてのデータを配列として配置できます。これにより、main_segments_history
を更新することはありません。
これは、基本的に、次のことを行います。
-- Move segments from dayly_segments to main_segment_history
INSERT INTO
main_segments_history
(id_segment, day, day_slices)
SELECT
id_segment, day,
(SELECT array_agg(slice)
FROM (SELECT slice
FROM dayly_segments s1
WHERE s1.id_segment = s0.id_segment AND s1.day = s0.day
ORDER BY id_slice) AS s2)
FROM
(SELECT DISTINCT
id_segment, day
FROM
dayly_segments s0
WHERE
day = '2017-01-01'
) AS s0 ;
-- Delete them from original
DELETE FROM
dayly_segments
WHERE
day = '2017-01-01' ;
-- At this point, you should also...
VACUUM dayly_segments ;
dbfiddle ここ
仮定:
$current_value
を見逃すことはありません。つまり、配列にはholesがありません。id_slice
には、増加するシーケンスの結果を割り当てることができます。整数値の代わりに、time
値だけを使用することもできます。