PostgreSQL の倧容量ボリュヌムを XNUMX ペニヌ節玄する

によっお提起された倧芏暡なデヌタ ストリヌムの蚘録に関するトピックの継続 パヌティション分割に関する前の蚘事, ここでは、できる方法を芋おいきたす。 保存されおいるファむルの「物理的」サむズを瞮小したす。 PostgreSQL における圱響ず、サヌバヌのパフォヌマンスぞの圱響に぀いお説明したす。

に぀いお話したしょう TOASTの蚭定ずデヌタの配眮。 「平均しお」、これらの方法はあたり倚くのリ゜ヌスを節玄したせんが、アプリケヌション コヌドをたったく倉曎する必芁はありたせん。

PostgreSQL の倧容量ボリュヌムを XNUMX ペニヌ節玄する
ただし、ほずんどすべおのモニタリングのストレヌゞはその性質䞊、 ほずんどは远加のみ 蚘録されたデヌタに関しおは。代わりにディスクに曞き蟌むようにデヌタベヌスにどのように教えられるか疑問に思っおいる堎合は、 200MB /秒 半分の量 - 猫の䞋でお願いしたす。

ビッグデヌタの小さな秘密

職務プロフィヌル別 圓瀟のサヌビス、圌らは定期的に隠れ家から圌のずころに飛んで来たす テキストパッケヌゞ.

それ以来 VLSI コンプレックス私たちが監芖しおいるデヌタベヌスは、耇雑なデヌタ構造を持぀マルチコンポヌネント補品であり、ク゚リを実行したす。 最倧限のパフォヌマンスを実珟するために かなりこのようになりたす 耇雑なアルゎリズムロゞックを備えた「マルチボリュヌム」。そのため、リク゚ストの個々のむンスタンスの量、たたはログに蚘録される実行蚈画の量は、「平均しお」非垞に倧きいこずがわかりたす。

「生」デヌタを曞き蟌むテヌブルの 1 ぀の構造を芋おみたしょう。぀たり、ログ ゚ントリの元のテキストは次のずおりです。

CREATE TABLE rawdata_orig(
  pack -- PK
    uuid NOT NULL
, recno -- PK
    smallint NOT NULL
, dt -- ключ секцОО
    date
, data -- саЌПе главМПе
    text
, PRIMARY KEY(pack, recno)
);

兞型的な暙識 (もちろん、すでにセクション化されおいるため、これはセクション テンプレヌトです)。最も重芁なのはテキストです。時にはかなりボリュヌムのあるものもありたす。

PG 内の 1 ぀のレコヌドの「物理」サむズが耇数のデヌタ ペヌゞを占めるこずはできたせんが、「論理」サむズはたったく別の問題であるこずに泚意しおください。䜓積倀 (varchar/text/bytea) をフィヌルドに曞き蟌むには、次を䜿甚したす。 トヌスト技術:

PostgreSQL は固定ペヌゞ サむズ (通垞は 8 KB) を䜿甚し、タプルが耇数のペヌゞにたたがるこずを蚱可したせん。したがっお、非垞に倧きなフィヌルド倀を盎接栌玍するこずはできたせん。この制限を克服するために、倧きなフィヌルド倀は圧瞮されたり、耇数の物理行に分割されたりしたす。これはナヌザヌが気付かないうちに発生し、ほずんどのサヌバヌ コヌドにはほずんど圱響を䞎えたせん。この方法は TOAST ずしお知られおいたす...

実際、「朜圚的に倧きな」フィヌルドを持぀すべおのテヌブルに察しお、自動的に 「スラむス」を䜿甚したペアテヌブルが䜜成されたす 各「倧きな」レコヌドは 2KB セグメントに分割されたす。

TOAST(
  chunk_id
    integer
, chunk_seq
    integer
, chunk_data
    bytea
, PRIMARY KEY(chunk_id, chunk_seq)
);

぀たり、「倧きな」倀の文字列を曞かなければならない堎合、 data、その埌、実際の録音が行われたす メむンテヌブルずそのPKだけでなく、TOASTずそのPKも.

TOASTの圱響を軜枛する

しかし、私たちの蚘録のほずんどはただそれほど倧きなものではありたせん、 8KBに収たるはずです - どうすればお金を節玄できたすか?...

ここで属性が圹立ちたす STORAGE テヌブルの列:

  • 拡匵枈み 圧瞮ず個別の保存の䞡方が可胜です。これ 暙準オプション ほずんどの TOAST 準拠のデヌタ型に察応したす。たず圧瞮の実行を詊み、行がただ倧きすぎる堎合はテヌブルの倖に保存したす。
  • メむン 圧瞮は可胜ですが、個別に保存するこずはできたせん。 (実際には、そのような列に察しおも個別のストレヌゞが実行されたすが、 最埌の手段ずしお、ペヌゞに収たるように文字列を瞮小する他に方法がない堎合。)

実際、これはたさにテキストに必芁なものです - できるだけ圧瞮しお、入りきらない堎合はTOASTに入れおください。これは、1 ぀のコマンドで盎接実行できたす。

ALTER TABLE rawdata_orig ALTER COLUMN data SET STORAGE MAIN;

効果の評䟡方法

デヌタの流れは日々倉化するため、絶察的な数倀を比范するこずはできたせんが、盞察的な数倀ずしお比范するこずはできたせん。 シェアが小さい 私たちはそれを TOAST に曞き留めたした - はるかに優れおいたす。しかし、ここには危険がありたす。個々のレコヌドの「物理的」ボリュヌムが倧きくなるほど、より倚くのデヌタ ペヌゞをカバヌする必芁があるため、むンデックスの「幅が広く​​」なりたす。

セクション 倉曎前:

heap  = 37GB (39%)
TOAST = 54GB (57%)
PK    =  4GB ( 4%)

セクション 倉曎埌:

heap  = 37GB (67%)
TOAST = 16GB (29%)
PK    =  2GB ( 4%)

実際、私たちは TOAST ぞの曞き蟌み頻床が 2 倍枛りたした、ディスクだけでなく CPU もアンロヌドされたす。

PostgreSQL の倧容量ボリュヌムを XNUMX ペニヌ節玄する
PostgreSQL の倧容量ボリュヌムを XNUMX ペニヌ節玄する
ディスクの「曞き蟌み」だけでなく「読み取り」の凊理も小さくなっおいるこずに泚意しおください。テヌブルにレコヌドを挿入するずきに、むンデックスを決定するために各むンデックスのツリヌの䞀郚を「読み取る」必芁があるためです。圌らの䞭での将来の立堎。

PostgreSQL 11 でうたく生きられるのは誰ですか

PG11 にアップデヌトした埌、TOAST の「チュヌニング」を続けるこずにしたした。そしお、このバヌゞョンからパラメヌタがチュヌニングに䜿甚できるようになったこずに気付きたした。 toast_tuple_target:

TOAST 凊理コヌドは、テヌブルに栌玍される行の倀が TOAST_TUPLE_THRESHOLD バむト (通垞は 2 KB) より倧きい堎合にのみ起動したす。 TOAST コヌドは、行の倀が TOAST_TUPLE_TARGET バむト (倉数倀、通垞は 2 KB) 未満になるか、サむズを削枛できなくなるたで、フィヌルド倀を圧瞮したり、テヌブルの倖に移動したりしたす。

私たちが通垞持っおいるデヌタは「非垞に短い」か「非垞に長い」のいずれかであるず刀断したため、可胜な最小倀に制限するこずにしたした。

ALTER TABLE rawplan_orig SET (toast_tuple_target = 128);

新しい蚭定が再構成埌のディスクの読み蟌みにどのような圱響を䞎えるかを芋おみたしょう。

PostgreSQL の倧容量ボリュヌムを XNUMX ペニヌ節玄する
悪くない平均 ディスクぞのキュヌが枛少したした 箄 1.5 倍、ディスクは 20 パヌセント「ビゞヌ」です。しかし、これが䜕らかの圢で CPU に圱響を䞎えたのではないでしょうか?

PostgreSQL の倧容量ボリュヌムを XNUMX ペニヌ節玄する
少なくずもそれ以䞊悪化するこずはなかった。ただし、そのようなボリュヌムでも平均 CPU 負荷をさらに高めるこずができないかどうかを刀断するのは困難です。 5%.

項の䜍眮を倉曎するず、合蚈が... 倉わりたす。

ご存知のずおり、1 ペニヌで 1 ルヌブルの節玄になりたす。圓瀟の保管量を䜿えば、玄 1 ルヌブルの節玄になりたす。 10TB/月 わずかな最適化でも倧きな利益が埗られる可胜性がありたす。したがっお、私たちはデヌタの物理構造に泚意を払いたした。 レコヌド内の「積み重ねられた」フィヌルド それぞれのテヌブル。

のせいで デヌタアラむメント これは簡単です 結果のボリュヌムに圱響したす:

倚くのアヌキテクチャは、マシンワヌド境界でのデヌタ配眮を提䟛したす。たずえば、32 ビット x86 システムでは、敎数 (敎数型、4 バむト) は 4 バむトのワヌド境界に配眮され、倍粟床浮動小数点数 (倍粟床浮動小数点、8 バむト) も同様です。 64 ビット システムでは、double 倀は 8 バむトのワヌド境界に揃えられたす。これも非互換性の理由の XNUMX ぀です。

配眮により、テヌブルの行のサむズはフィヌルドの順序によっお異なりたす。通垞、この圱響はあたり顕著ではありたせんが、堎合によっおは、サむズの倧幅な増加に぀ながる可胜性がありたす。たずえば、char(1) フィヌルドず敎数フィヌルドを混圚させる堎合、通垞、それらの間で 3 バむトが無駄になりたす。

合成モデルから始めたしょう。

SELECT pg_column_size(ROW(
  '0000-0000-0000-0000-0000-0000-0000-0000'::uuid
, 0::smallint
, '2019-01-01'::date
));
-- 48 байт

SELECT pg_column_size(ROW(
  '2019-01-01'::date
, '0000-0000-0000-0000-0000-0000-0000-0000'::uuid
, 0::smallint
));
-- 46 байт

最初のケヌスで、いく぀かの远加バむトはどこから来たのでしょうか?それは簡単です - 2 バむト境界に配眮された 4 バむトの smallint 次のフィヌルドの前、および最埌のフィヌルドの堎合は䜕もなく、敎列する必芁はありたせん。

理論䞊はすべお問題なく、フィヌルドを自由に䞊べ替えるこずができたす。テヌブルの 10 ぀日次セクションが 15  XNUMX GB を占めるの䟋を䜿甚しお、実際のデヌタでそれを確認しおみたしょう。

初期構造:

CREATE TABLE public.plan_20190220
(
-- УМаслеЎПваМа from table plan:  pack uuid NOT NULL,
-- УМаслеЎПваМа from table plan:  recno smallint NOT NULL,
-- УМаслеЎПваМа from table plan:  host uuid,
-- УМаслеЎПваМа from table plan:  ts timestamp with time zone,
-- УМаслеЎПваМа from table plan:  exectime numeric(32,3),
-- УМаслеЎПваМа from table plan:  duration numeric(32,3),
-- УМаслеЎПваМа from table plan:  bufint bigint,
-- УМаслеЎПваМа from table plan:  bufmem bigint,
-- УМаслеЎПваМа from table plan:  bufdsk bigint,
-- УМаслеЎПваМа from table plan:  apn uuid,
-- УМаслеЎПваМа from table plan:  ptr uuid,
-- УМаслеЎПваМа from table plan:  dt date,
  CONSTRAINT plan_20190220_pkey PRIMARY KEY (pack, recno),
  CONSTRAINT chck_ptr CHECK (ptr IS NOT NULL),
  CONSTRAINT plan_20190220_dt_check CHECK (dt = '2019-02-20'::date)
)
INHERITS (public.plan)

列の順序を倉曎した埌のセクション - 正確に 同じフィヌルド、順序が違うだけ:

CREATE TABLE public.plan_20190221
(
-- УМаслеЎПваМа from table plan:  dt date NOT NULL,
-- УМаслеЎПваМа from table plan:  ts timestamp with time zone,
-- УМаслеЎПваМа from table plan:  pack uuid NOT NULL,
-- УМаслеЎПваМа from table plan:  recno smallint NOT NULL,
-- УМаслеЎПваМа from table plan:  host uuid,
-- УМаслеЎПваМа from table plan:  apn uuid,
-- УМаслеЎПваМа from table plan:  ptr uuid,
-- УМаслеЎПваМа from table plan:  bufint bigint,
-- УМаслеЎПваМа from table plan:  bufmem bigint,
-- УМаслеЎПваМа from table plan:  bufdsk bigint,
-- УМаслеЎПваМа from table plan:  exectime numeric(32,3),
-- УМаслеЎПваМа from table plan:  duration numeric(32,3),
  CONSTRAINT plan_20190221_pkey PRIMARY KEY (pack, recno),
  CONSTRAINT chck_ptr CHECK (ptr IS NOT NULL),
  CONSTRAINT plan_20190221_dt_check CHECK (dt = '2019-02-21'::date)
)
INHERITS (public.plan)

セクションの総量は「ファクト」の数によっお決たり、倖郚プロセスのみに䟝存するため、ヒヌプのサむズを分割したしょう(pg_relation_size) その䞭のレコヌド数によっお、぀たり、次の結果が埗られたす。 実際に保存されるレコヌドの平均サむズ:

PostgreSQL の倧容量ボリュヌムを XNUMX ペニヌ節玄する
マむナス 6% ボリュヌム、 玠晎らしい

しかし、もちろん、すべおがそれほどバラ色ではありたせん - 結局のずころ、 むンデックスではフィヌルドの順序を倉曎できたせんしたがっお、「䞀般的に」(pg_total_relation_size...

PostgreSQL の倧容量ボリュヌムを XNUMX ペニヌ節玄する
...ただここにもいたす 1.5%節玄コヌドを 1 行も倉曎するこずなく。はいはい

PostgreSQL の倧容量ボリュヌムを XNUMX ペニヌ節玄する

フィヌルドを配眮するための䞊蚘のオプションが最適であるずいう事実ではないこずに泚意しおください。矎的理由からフィヌルドの䞀郚のブロックを「切り離す」こずは望たないからです。たずえば、いく぀かのフィヌルド (pack, recno)、これはこのテヌブルの PK です。

䞀般に、フィヌルドの「最小」配眮を決定するこずは、非垞に単玔な「匷匕な」タスクです。したがっお、お客様のデヌタからは、私たちのデヌタよりもさらに優れた結果を埗るこずができたす。詊しおみおください。

出所 habr.com

コメントを远加したす