Gorde zentimo bat PostgreSQL-n bolumen handietan

Sortutako datu-korronte handiak grabatzearen gaiarekin jarraituz zatiketari buruzko aurreko artikulua, honetan ahal duzun moduak aztertuko ditugu gordetakoaren tamaina "fisikoa" murriztu PostgreSQL-n, eta zerbitzariaren errendimenduan duten eragina.

buruz hitz egingo dugu TOAST ezarpenak eta datuen lerrokatzea. "Batez beste", metodo hauek ez dute baliabide gehiegi aurreztuko, baina aplikazioaren kodea batere aldatu gabe.

Gorde zentimo bat PostgreSQL-n bolumen handietan
Hala ere, gure esperientzia oso emankorra izan da zentzu honetan, izan ere, ia edozein monitorizazio gordetzea bere izaeragatik da. gehienetan eranskin-soilik erregistratutako datuei dagokienez. Eta galdetzen bazaizu nola irakatsi dezakezun datu-baseari diskoan idazten ordez 200MB / s erdia - mesedez katu azpian.

Big dataren sekretu txikiak

Lanpostuaren profilaren arabera gure zerbitzua, erregularki hegan egiten diote gordelekuetatik testu paketeak.

Eta geroztik VLSI konplexuazeinaren datu-basea kontrolatzen dugun osagai anitzeko produktua da, datu-egitura konplexuak dituena, ondoren kontsultak errendimendurik handiena lortzeko nahiko horrela atera "bolumen anitzeko" logika algoritmiko konplexuarekin. Beraz, eskaera baten instantzia bakoitzaren edo ondoriozko exekuzio-planaren bolumena datorkigun erregistroan "batez beste" nahiko handia da.

Ikus dezagun datu "gordinak" idazten ditugun tauletako baten egitura; hau da, hona hemen erregistroko sarrerako jatorrizko testua:

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

Seinale tipiko bat (dagoeneko atalkatuta, noski, beraz, hau atal txantiloia da), non garrantzitsuena testua den. Batzuetan nahiko bolumentsua.

Gogoratu PG bateko erregistro baten tamaina "fisikoak" ezin duela datu orri bat baino gehiago okupatu, baina tamaina "logikoa" guztiz bestelakoa da. Eremu batean balio bolumetriko bat (varchar/text/bytea) idazteko, erabili TOAST teknologia:

PostgreSQL-k orrialde-tamaina finkoa erabiltzen du (normalean 8 KB), eta ez du onartzen tuplek hainbat orrialdetan zabaltzea. Hori dela eta, ezinezkoa da eremu-balio handiak zuzenean gordetzea. Muga hori gainditzeko, eremuen balio handiak konprimitu eta/edo zatitu egiten dira hainbat lerro fisikotan. Hau erabiltzaileak oharkabean gertatzen da eta eragin txikia du zerbitzari-kode gehienetan. Metodo hau TOAST bezala ezagutzen da...

Izan ere, "potentzialki handiak" eremuak dituen taula bakoitzeko, automatikoki "Xerraketa" duen mahai parekatua sortzen da Erregistro "handi" bakoitza 2KB-ko segmentuetan:

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

Hau da, balio “handia” duen kate bat idatzi behar badugu data, orduan benetako grabazioa gertatuko da ez bakarrik mahai nagusiari eta bere PKri, baita TOAST eta bere PKri ere.

TOAST eragina murriztea

Baina gure disko gehienak oraindik ez dira horren handiak, 8KB-n sartu behar da - Nola aurreztu dezaket dirua honetan?...

Horra datorkigu atributua lagungarri STORAGE mahaiaren zutabean:

  • EXTENDED konpresioa eta biltegiratze bereizia ahalbidetzen du. Hau aukera estandarra TOAST bat datozen datu-mota gehienetarako. Lehenik konpresioa egiten saiatzen da, eta, ondoren, mahaitik kanpo gordetzen du errenkada oraindik handiegia bada.
  • NAGUSIAK konpresioa ahalbidetzen du, baina ez bereizita biltegiratzea. (Izan ere, halako zutabeetarako biltegiratze bereizia egingo da, baina soilik azken aukera gisa, katea txikitzeko beste modurik ez dagoenean orrialdera egokitzeko.)

Izan ere, horixe da testurako behar duguna - ahalik eta gehien konprimitu, eta batere kabitzen ez bada, TOASTetan jarri. Hau zuzenean egin daiteke hegan, komando batekin:

ALTER TABLE rawdata_orig ALTER COLUMN data SET STORAGE MAIN;

Nola ebaluatu eragina

Datu-fluxua egunero aldatzen denez, ezin ditugu zenbaki absolutuak konparatu, termino erlatiboetan baizik kuota txikiagoa TOAST-en idatzi genuen, askoz hobeto. Baina arrisku bat dago hemen - erregistro bakoitzaren bolumen "fisikoa" zenbat eta handiagoa izan, orduan eta indizea "zabalagoa" bihurtzen da, datu orrialde gehiago estali behar ditugulako.

Atala aldaketen aurretik:

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

Atala aldaketen ondoren:

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

Izan ere, guk TOAST-i 2 aldiz gutxiagotan idazten hasi zen, diskoa ez ezik, CPUa ere deskargatu zuena:

Gorde zentimo bat PostgreSQL-n bolumen handietan
Gorde zentimo bat PostgreSQL-n bolumen handietan
Kontuan izanen dut diskoa “irakurtzean” ere txikiagotu egin garela, ez “idazketan” bakarrik; izan ere, erregistro bat taula batean sartzean, indize bakoitzaren zuhaitzaren zati bat ere “irakurri” behar dugu bere zehazteko. etorkizuneko posizioa horietan.

Nor bizi daiteke ondo PostgreSQL 11-n

PG11-ra eguneratu ondoren, TOAST "sintonizatzen" jarraitzea erabaki genuen eta bertsio honetatik abiatuta parametroa sintonizatzeko erabilgarri zegoela ohartu ginen. toast_tuple_target:

TOAST prozesatzeko kodea taulan gorde beharreko errenkada-balioa TOAST_TUPLE_THRESHOLD byte baino handiagoa denean (normalean 2 KB) baino ez da abiarazten. TOAST kodeak eremuen balioak konprimitu edo/eta eramango ditu taulatik kanpo errenkada-balioa TOAST_TUPLE_TARGET byte baino txikiagoa izan arte (balio aldakorra, normalean 2 KB) edo tamaina murriztu ezin den arte.

Normalean ditugun datuak “oso laburrak” edo “oso luzeak” direla erabaki genuen, beraz, ahalik eta balio minimora mugatzea erabaki genuen:

ALTER TABLE rawplan_orig SET (toast_tuple_target = 128);

Ikus dezagun ezarpen berriek birkonfiguratu ondoren diskoaren kargari nola eragiten dioten:

Gorde zentimo bat PostgreSQL-n bolumen handietan
Ez dago gaizki! Batez bestekoa diskorako ilara txikitu egin da gutxi gorabehera 1.5 aldiz, eta diskoa "okupatuta" ehuneko 20 da! Baina agian horrek nolabait PUZari eragin dio?

Gorde zentimo bat PostgreSQL-n bolumen handietan
Ez zen okerrago egin behintzat. Hala ere, zaila da epaitzea bolumen horiek ere ezin badute CPU batez besteko karga handiagoa igo 5%.

Baldintzen lekuak aldatuz, batura... aldaketak!

Dakizuenez, zentimo batek errublo bat aurrezten du, eta gure biltegiratze-bolumenekin hori da 10TB/hilean optimizazio txiki batek ere irabazi ona eman dezake. Hori dela eta, gure datuen egitura fisikoari erreparatu diogu, nola zehazki Erregistroaren barruan "pilatutako" eremuak taula bakoitza.

Horregatik datuen lerrokatzea hau zuzena da ondoriozko bolumena eragiten du:

Arkitektura askok datuen lerrokatzea eskaintzen dute makina hitzen mugetan. Adibidez, 32 biteko x86 sisteman, zenbaki osoak (osoko mota, 4 byte) 4 byteko hitz-mugan lerrokatuko dira, eta doitasun bikoitzeko koma mugikorreko zenbakiak (doitasun bikoitzeko koma mugikorrean, 8 byte). Eta 64 biteko sisteman, balio bikoitzak 8 byteko hitzen mugetara lerrokatuko dira. Hau da bateraezintasunaren beste arrazoi bat.

Lerrokatzea dela eta, taula-errenkada baten tamaina eremuen ordenaren araberakoa da. Normalean efektu hori ez da oso nabaria, baina kasu batzuetan tamaina handitzea nabarmena izan daiteke. Adibidez, char(1) eta osoko eremuak nahasten badituzu, normalean 3 byte alferrik galduko dira bien artean.

Has gaitezen eredu sintetikoekin:

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

Nondik atera ziren pare bat byte gehigarri lehen kasuan? Sinplea da - 2 byte txikia 4 byteko mugan lerrokatuta hurrengo eremuaren aurretik, eta azkena denean, ez dago ezer eta ez dago lerrokatzeko beharrik.

Teorian, dena ondo dago eta eremuak nahi duzun moduan berrantola ditzakezu. Egiazta ditzagun datu errealetan tauletako baten adibidea erabiliz, eguneroko atalak 10-15 GB okupatzen dituena.

Hasierako egitura:

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)

Zutabeen ordena aldatu ondoren atala - zehazki eremu berdinak, ordena ezberdina besterik ez:

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)

Atalaren guztizko bolumena "gertaera" kopuruaren arabera zehazten da eta kanpoko prozesuen araberakoa da soilik, beraz, zatitu dezagun pilaren tamaina (pg_relation_size) bertan dauden erregistro kopuruaren arabera - hau da, lortzen dugu benetako gordetako erregistroaren batez besteko tamaina:

Gorde zentimo bat PostgreSQL-n bolumen handietan
Minus %6 bolumena, Bikaina!

Baina dena, noski, ez da hain arrosa - azken finean, indizeetan ezin dugu eremuen ordena aldatu, eta, beraz, "oro har" (pg_total_relation_size) ...

Gorde zentimo bat PostgreSQL-n bolumen handietan
...oraindik ere hemen %1.5 aurreztukode lerro bakar bat ere aldatu gabe. Bai bai!

Gorde zentimo bat PostgreSQL-n bolumen handietan

Kontuan izan dut eremuak antolatzeko goiko aukera ez dela egokiena dela. Ez dituzulako eremu bloke batzuk "urratu" nahi arrazoi estetikoengatik - adibidez, pare bat (pack, recno), hau da, taula honetako PK.

Oro har, eremuen "gutxieneko" antolamendua zehaztea "indar gordina" lan nahiko sinplea da. Hori dela eta, zure datuetatik gureak baino emaitza are hobeak lor ditzakezu - proba ezazu!

Iturria: www.habr.com

Gehitu iruzkin berria