Sparaðu eyri fyrir mikið magn í PostgreSQL

Áframhaldandi efnisatriði að taka upp stóra gagnastrauma sem vakna með fyrri grein um skiptingu, í þessu munum við skoða þær leiðir sem þú getur draga úr „líkamlegri“ stærð geymslunnar í PostgreSQL, og áhrif þeirra á frammistöðu netþjónsins.

Við munum tala um TOAST stillingar og gagnajöfnun. „Að meðaltali“ munu þessar aðferðir ekki spara of mikið úrræði, en án þess að breyta forritskóðanum yfirleitt.

Sparaðu eyri fyrir mikið magn í PostgreSQL
Hins vegar reyndist reynsla okkar mjög afkastamikil í þessu sambandi, þar sem geymsla á nánast hvaða vöktun sem er í eðli sínu að mestu eingöngu viðauka hvað varðar skráð gögn. Og ef þú ert að spá í hvernig þú getur kennt gagnagrunninum að skrifa á disk í staðinn 200MB / s helmingi meira - vinsamlegast undir kött.

Lítil leyndarmál stórra gagna

Eftir starfssniði þjónustu okkar, þeir fljúga reglulega til hans úr bæli textapakka.

Og síðan VLSI flókiðgagnagrunnurinn sem við fylgjumst með er fjölþætt vara með flóknu gagnaskipulagi, síðan fyrirspurnum fyrir hámarksafköst koma alveg svona út „margt bindi“ með flókinni reikniritrökfræði. Þannig að rúmmál hvers einstaks tilviks beiðni eða framkvæmdaáætlunarinnar sem af því leiðir í skránni sem kemur til okkar reynist vera „að meðaltali“ nokkuð mikið.

Við skulum skoða uppbyggingu einnar af töflunum sem við skrifum „hrá“ gögn í - það er að segja, hér er upprunalegi textinn úr færsluskránni:

CREATE TABLE rawdata_orig(
  pack -- PK
    uuid NOT NULL
, recno -- PK
    smallint NOT NULL
, dt -- ключ секции
    date
, data -- самое главное
    text
, PRIMARY KEY(pack, recno)
);

Dæmigert merki (nú þegar skipt, auðvitað, þannig að þetta er kaflasniðmát), þar sem það mikilvægasta er textinn. Stundum frekar umfangsmikið.

Mundu að „líkamleg“ stærð einnar færslu í PG getur ekki tekið meira en eina síðu af gögnum, en „rökrétt“ stærðin er allt annað mál. Til að skrifa rúmmálsgildi (varchar/text/bytea) í reit, notaðu TOAST tækni:

PostgreSQL notar fasta síðustærð (venjulega 8 KB) og leyfir ekki túllum að spanna margar síður. Þess vegna er ómögulegt að geyma mjög stór svæðisgildi beint. Til að sigrast á þessari takmörkun eru stórum sviðsgildum þjappað saman og/eða skipt yfir margar líkamlegar línur. Þetta gerist óséður af notandanum og hefur lítil áhrif á flestan netþjónakóða. Þessi aðferð er þekkt sem TOAST...

Reyndar, sjálfkrafa fyrir hvert borð með „hugsanlega stórum“ reitum pöruð borð með „sneið“ er búin til hver „stór“ skrá í 2KB hlutum:

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

Það er að segja ef við þurfum að skrifa streng með „stórt“ gildi data, þá mun raunveruleg upptaka eiga sér stað ekki aðeins til aðalborðsins og PK þess, heldur einnig TOAST og PK þess.

Að draga úr áhrifum TOAST

En flestar plötur okkar eru samt ekki svo stórar, ætti að passa inn í 8KB - Hvernig get ég sparað peninga á þessu? ..

Þetta er þar sem eiginleikinn kemur okkur til hjálpar STORAGE við töfludálkinn:

  • ÚTVERT leyfir bæði þjöppun og aðskilda geymslu. Þetta staðall valkostur fyrir flestar TOAST samhæfðar gagnagerðir. Það reynir fyrst að framkvæma þjöppun, geymir það síðan fyrir utan borðið ef röðin er enn of stór.
  • MAIN leyfir þjöppun en ekki aðskilda geymslu. (Reyndar verður aðskilin geymsla enn framkvæmd fyrir slíka dálka, en aðeins sem síðasta úrræði, þegar engin önnur leið er til að minnka strenginn þannig að hann passi á síðuna.)

Reyndar er þetta nákvæmlega það sem við þurfum fyrir textann - þjappaðu því eins mikið og mögulegt er og ef það passar alls ekki skaltu setja það í TOAST. Þetta er hægt að gera beint á flugu, með einni skipun:

ALTER TABLE rawdata_orig ALTER COLUMN data SET STORAGE MAIN;

Hvernig á að meta áhrifin

Þar sem gagnaflæðið breytist á hverjum degi getum við ekki borið saman heildartölur, heldur hlutfallslega minni hlut Við skrifuðum það niður í TOAST - svo miklu betra. En það er hætta hér - því stærra sem „líkamlegt“ rúmmál hverrar einstakrar skráar er, því „breiðari“ verður vísitalan, vegna þess að við verðum að ná yfir fleiri síður af gögnum.

Kafli fyrir breytingar:

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

Kafli eftir breytingar:

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

Reyndar erum við byrjaði að skrifa á TOAST 2 sinnum sjaldnar, sem affermdi ekki aðeins diskinn, heldur einnig CPU:

Sparaðu eyri fyrir mikið magn í PostgreSQL
Sparaðu eyri fyrir mikið magn í PostgreSQL
Ég tek það fram að við höfum líka orðið minni í að „lesa“ diskinn, ekki aðeins „skrifa“ - þar sem þegar við setjum færslu inn í töflu verðum við líka að „lesa“ hluta af tré hvers vísitölu til að ákvarða framtíðarstöðu í þeim.

Hver getur lifað vel á PostgreSQL 11

Eftir að hafa uppfært í PG11 ákváðum við að halda áfram að „stilla“ TOAST og tókum eftir því að frá og með þessari útgáfu er færibreytan toast_tuple_target:

TOAST vinnslukóði ræsir aðeins þegar línugildið sem á að geyma í töflunni er stærra en TOAST_TUPLE_THRESHOLD bæti (venjulega 2 KB). TOAST kóðinn mun þjappa og/eða færa svæðisgildi út úr töflunni þar til línugildið verður minna en TOAST_TUPLE_TARGET bæti (breytilegt gildi, einnig venjulega 2 KB) eða ekki er hægt að minnka stærðina.

Við ákváðum að gögnin sem við höfum venjulega eru annaðhvort „mjög stutt“ eða „mjög löng“, svo við ákváðum að takmarka okkur við lágmarks mögulega gildi:

ALTER TABLE rawplan_orig SET (toast_tuple_target = 128);

Við skulum sjá hvernig nýju stillingarnar höfðu áhrif á hleðslu disksins eftir endurstillingu:

Sparaðu eyri fyrir mikið magn í PostgreSQL
Ekki slæmt! Meðaltal biðröð á diskinn hefur minnkað um það bil 1.5 sinnum og diskurinn „upptekinn“ er 20 prósent! En kannski hafði þetta einhvern veginn áhrif á CPU?

Sparaðu eyri fyrir mikið magn í PostgreSQL
Það fór allavega ekki verr. Þó er erfitt að dæma hvort jafnvel slíkt magn geti samt ekki hækkað meðaltal CPU hleðslu hærra 5%.

Með því að skipta um staði hugtakanna breytist summan...!

Eins og þú veist sparar eyrir rúblur og með geymslumagninu okkar er það um það bil 10TB/mánuði jafnvel smá hagræðing getur gefið góðan hagnað. Þess vegna gáfum við gaum að líkamlegri uppbyggingu gagna okkar - hvernig nákvæmlega „staflað“ reitir inni í skránni hvert borð.

Vegna þess að gagnajöfnun þetta er beint fram hefur áhrif á magnið sem myndast:

Margir arkitektúrar veita gagnajöfnun á vélorðamörkum. Til dæmis, á 32-bita x86 kerfi, verða heiltölur (heildtölugerð, 4 bæti) stillt á 4-bæta orðamörk, sem og tvöfaldar nákvæmar fljótandi tölur (tvöfaldur nákvæmni flottölur, 8 bæti). Og á 64-bita kerfi verða tvöföld gildi stillt við 8-bæta orðamörk. Þetta er önnur ástæða fyrir ósamrýmanleika.

Vegna jöfnunar fer stærð töflulínu eftir röð reitanna. Venjulega eru þessi áhrif ekki mjög áberandi, en í sumum tilfellum getur það leitt til verulegrar stærðaraukningar. Til dæmis, ef þú blandar saman char(1) og heiltölusviðum, verða venjulega 3 bæti til spillis á milli þeirra.

Við skulum byrja með gervilíkön:

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 байт

Hvaðan komu nokkur aukabæt í fyrra tilvikinu? Það er einfalt - 2-bæta smallint stillt á 4-bæta mörk fyrir næsta svið, og þegar það er það síðasta, er ekkert og engin þörf á að stilla.

Fræðilega séð er allt í lagi og þú getur endurraðað reitunum eins og þú vilt. Við skulum athuga það á raunverulegum gögnum með því að nota dæmi um eina af töflunum, daglegur hluti sem tekur 10-15GB.

Upphafleg uppbygging:

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)

Hluti eftir að breyta röð dálka - nákvæmlega sömu reitir, bara mismunandi röð:

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)

Heildarrúmmál hlutans ræðst af fjölda „staðreynda“ og fer aðeins eftir ytri ferlum, svo við skulum skipta stærðinni á haugnum (pg_relation_size) eftir fjölda skráa í því - það er, við fáum meðalstærð raunverulegrar geymdar skráar:

Sparaðu eyri fyrir mikið magn í PostgreSQL
Mínus 6% rúmmál, Frábært!

En allt er auðvitað ekki svo bjart - þegar allt kemur til alls, í vísitölum getum við ekki breytt röð reita, og því „almennt“ (pg_total_relation_size) ...

Sparaðu eyri fyrir mikið magn í PostgreSQL
... enn hér líka sparað 1.5%án þess að breyta einni kóðalínu. Já já!

Sparaðu eyri fyrir mikið magn í PostgreSQL

Ég tek fram að ofangreindur valkostur til að raða völlum er ekki sú staðreynd að hann sé bestur. Vegna þess að þú vilt ekki „rífa“ suma reitir af fagurfræðilegum ástæðum - til dæmis, par (pack, recno), sem er PK fyrir þessa töflu.

Almennt séð er það frekar einfalt verkefni að ákvarða „lágmarks“ fyrirkomulag reita. Þess vegna geturðu fengið enn betri niðurstöður úr gögnunum þínum en okkar - reyndu það!

Heimild: www.habr.com

Bæta við athugasemd