Li ser cildên mezin di PostgreSQL de quruşek hilînin

Berdewamkirina mijara tomarkirina herikên daneyên mezin ên ku ji hêla ve hatî rakirin gotara berê di derbarê dabeşkirinê de, di vê yekê de em ê li awayên ku hûn dikarin bibînin mezinahiya "fizîkî" ya hilanînê kêm bikin li PostgreSQL, û bandora wan li ser performansa serverê.

Em ê biaxivin Mîhengên TOAST û berhevkirina daneyê. "Bi navînî," van rêbazan dê gelek çavkaniyan xilas nekin, lê bêyî ku koda serîlêdanê bi tevahî biguherînin.

Li ser cildên mezin di PostgreSQL de quruşek hilînin
Lêbelê, ezmûna me di vî warî de pir hilberîner derket, ji ber ku hilanîna hema hema her çavdêriyê ji hêla cewherê xwe ve ye bi piranî pêvek-tenê di warê daneyên tomarkirî de. Û heke hûn meraq dikin ka hûn çawa dikarin databasê fêrî nivîsandina dîskê bikin 200MB / s nîv bi qasî - ji kerema xwe binê pisîkê.

Sirên piçûk ên daneyên mezin

Li gorî profîla kar xizmeta me, ew bi rêkûpêk ji hêlînên wî difirin pakêtên nivîsê.

Since ji ber ku kompleksa VLSIdatabasa ku em çavdêrî dikin hilberek pir-pêkhatî ye ku bi strukturên daneya tevlihev e, dûv re lêpirsîn ji bo performansa herî zêde pir bi vî rengî derkeve "pir-volume" bi mantiqa algorîtmîkî ya tevlihev. Ji ber vê yekê qebareya her mînakek kesane ya daxwazek an plansaziya darvekirinê ya encam di têketina ku ji me re tê "bi navînî" pir mezin dibe.

Ka em li avahiya yek ji tabloyên ku em daneya "xew" tê de dinivîsin binêrin - ango, li vir nivîsa orîjînal ji têketina têketinê ye:

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

Nîşanek tîpîk (bê guman, jixwe veqetandî ye, ji ber vê yekê ev şablonek beşê ye), ku ya herî girîng nivîs e. Carinan pir mezin.

Bînin bîra xwe ku mezinahiya "fizîkî" ya yek tomarek di PG-ê de nikare zêdetirî yek rûpelek daneyê dagir bike, lê mezinahiya "mantiqî" mijarek bi tevahî cûda ye. Ji bo nivîsandina nirxek volumetric (varchar/text/bytea) li zeviyek, bikar bînin teknolojiya TOAST:

PostgreSQL mezinahiyek rûpelek sabît (bi gelemperî 8 KB) bikar tîne, û rê nade ku tuples çend rûpelan vegerînin. Ji ber vê yekê, ne gengaz e ku meriv rasterast nirxên zeviyê pir mezin hilîne. Ji bo derbaskirina vê sînorkirinê, nirxên zeviyê yên mezin li ser gelek xêzên laşî têne berhev kirin û/an parçe kirin. Ev ji hêla bikarhêner ve nayê dîtin û bandorek piçûk li ser piraniya koda serverê dike. Ev rêbaz wekî TOAST tê zanîn ...

Bi rastî, ji bo her tabloya bi qadên "bi potansiyel mezin", bixweber tabloyek hevgirtî ya bi "slicing" tê çêkirin her tomarek "mezin" di beşên 2KB de:

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

Ango ger divê em rêzek bi nirxek “mezin” binivîsin data, wê hingê tomarkirina rastîn dê çêbibe ne tenê ji maseya sereke û PK-ya wê, lê di heman demê de ji TOAST û PK-ya wê re jî.

Kêmkirina bandora TOAST

Lê piraniya tomarên me hîn ne ew qas mezin in, divê di 8KB de cih bigire - Ez çawa dikarim li ser vê yekê pereyan teserûf bikim?..

Li vir taybetmendî tê alîkariya me STORAGE li stûna sifrê:

  • BİXWÎNE hem compression û hem jî hilanîna veqetandî dihêle. Ev option standard ji bo piraniya celebên daneya lihevhatî TOAST. Ew pêşî hewl dide ku berhevkirinê pêk bîne, dûv re wê li derveyî maseyê hilîne ger rêz hîn jî pir mezin be.
  • DESTÊ destûrê dide kompresê lê ne hilanîna veqetandî. (Bi rastî, hilanîna veqetandî dê hîn jî ji bo stûnên weha were kirin, lê tenê wek çareya dawî, gava ku rêyek din tune ku rêzê piçûk bike da ku ew li ser rûpelê bicîh bibe.)

Bi rastî, tiştê ku em ji bo nivîsê hewce ne ev e - bi qasî ku gengaz be wê biqelînin, û heke ew qet neqewime, wê têxin nav TOAST. Ev dikare rasterast li ser firînê, bi yek fermanê were kirin:

ALTER TABLE rawdata_orig ALTER COLUMN data SET STORAGE MAIN;

Meriv çawa bandorê dinirxîne

Ji ber ku herikîna daneyê her roj diguhere, em nekarin hejmarên bêkêmasî, lê bi şertên nisbî bidin ber hev para piçûktir Me ew di TOAST de nivîsand - ew qas çêtir. Lê li vir xeterek heye - her ku hejmûna "fizîkî" ya her tomarek kesane mezintir bibe, index "berfireh" dibe, ji ber ku pêdivî ye ku em bêtir rûpelên daneyê veşêrin.

Liq berî guhertinan:

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

Liq piştî guhertinan:

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

Bi rastî, em 2 caran kêmtir dest bi nivîsandina TOAST kir, ku ne tenê dîskê, lê di heman demê de CPU jî dakêşand:

Li ser cildên mezin di PostgreSQL de quruşek hilînin
Li ser cildên mezin di PostgreSQL de quruşek hilînin
Ez ê bala xwe bidim ku em di "xwendina" dîskê de jî piçûktir bûne, ne tenê "nivîsandin" - ji ber ku dema tomarek têxin nav tabloyek, di heman demê de pêdivî ye ku em beşek ji dara her nîşanekê jî "bixwînin" da ku wê diyar bikin. helwesta pêşerojê di wan de.

Kî dikare li ser PostgreSQL 11 baş bijî

Piştî nûvekirina PG11, me biryar da ku em "tuning" TOAST bidomînin û me dît ku ji vê guhertoyê dest pê dike parametre toast_tuple_target:

Koda pêvajoyê ya TOAST tenê dema ku nirxa rêzê ya ku di tabloyê de were hilanîn ji TOAST_TUPLE_THRESHOLD bytes (bi gelemperî 2 KB) mezintir be, dişewite. Koda TOAST dê nirxên zeviyê ji tabloyê biqelişîne û/an bikişîne heya ku nirxa rêzê ji TOAST_TUPLE_TARGET bytes (nirxa guhêrbar, di heman demê de bi gelemperî 2 KB) kêmtir bibe an mezinahî neyê kêm kirin.

Me biryar da ku daneyên ku em bi gelemperî hene an "pir kurt" an "pir dirêj" in, ji ber vê yekê me biryar da ku em xwe bi nirxa herî hindiktirîn sînordar bikin:

ALTER TABLE rawplan_orig SET (toast_tuple_target = 128);

Ka em bibînin ka mîhengên nû çawa bandor li barkirina dîskê piştî veavakirinê kir:

Li ser cildên mezin di PostgreSQL de quruşek hilînin
Xerab nîne! Navoser rêza dîskê kêm bûye Nêzîkî 1.5 carî, û dîskê "mijûl" ji sedî 20 e! Lê dibe ku ev bi rengek bandor li CPU-yê kir?

Li ser cildên mezin di PostgreSQL de quruşek hilînin
Qe nebe ew xerabtir nebû. Her çend, dijwar e ku meriv dadbar bike ger cildên weha hîn jî nekarin barkirina navînî ya CPU-yê bilindtir bikin 5%.

Bi guherandina cîhên terman, hevok... diguhere!

Wekî ku hûn dizanin, quruşek rubleyek xilas dike, û bi cildên hilanîna me re ew e 10TB/mehê tewra xweşbîniyek piçûk jî dikare qezencek baş bide. Ji ber vê yekê, me bala xwe da avahiya fizîkî ya daneyên xwe - çawa bi rastî Zeviyên "lihevkirî" di hundurê tomarê de her yek ji tabloyan.

Ji ber ku ji ber berhevdana daneyan ev rasterast li pêş e bandor li ser volume encam dike:

Gelek mîmarî li ser sînorên peyva makîneyê lihevhatina daneyê peyda dikin. Mînakî, li ser pergalek 32-bit x86, hejmarên bêkêmasî (cûreya jimare, 4 byte) dê li ser sînorê peyva 4-byte bêne rêz kirin, her weha dê jimareyên xala herikînê ya rast du qat bikin (xala herikandinê ya ducarî, 8 byte). Û li ser pergalek 64-bit, nirxên ducar dê li ser sînorên peyvan 8-byte bêne rêz kirin. Ev jî sedemeke din a lihevnekirinê ye.

Ji ber lihevkirinê, mezinahiya rêzek tabloyê bi rêza qadan ve girêdayî ye. Bi gelemperî ev bandor ne pir xuya ye, lê di hin rewşan de ew dikare bibe sedema zêdebûna mezinbûnê. Mînakî, heke hûn zeviyên char (1) û jimarek tevhev tevlihev bikin, dê bi gelemperî di navbera wan de 3 bytes winda bibin.

Ka em bi modelên sentetîk dest pê bikin:

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

Di doza yekem de çend bytên zêde ji ku derketin? Ew hêsan e - 2-byte piçûk li ser sînorê 4-byte li hev kirin berî qada paşîn, û gava ku ew ya paşîn be, tiştek û ne hewce ye ku meriv hevûdu bike.

Di teoriyê de, her tişt baş e û hûn dikarin zeviyan wekî ku hûn dixwazin ji nû ve saz bikin. Ka em bi mînaka yek ji tabloyan, beşa rojane ya ku 10-15 GB digire, li ser daneyên rastîn kontrol bikin.

Struktura destpêkê:

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)

Beşa piştî guheztina rêzika stûnê - tam heman zeviyan, tenê rêzek cûda:

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)

Hêjmara giştî ya beşê ji hêla hejmara "rastiyan" ve tête diyar kirin û tenê bi pêvajoyên derveyî ve girêdayî ye, ji ber vê yekê em ê mezinahiya girikê dabeş bikin (pg_relation_size) bi hejmara tomarên tê de - ango, em distînin mezinahiya navîn ya qeyda hilandî ya rastîn:

Li ser cildên mezin di PostgreSQL de quruşek hilînin
Minus 6% volume, Ecêb!

Lê her tişt, bê guman, ne ew qas gul e - paşî, di indexan de em nikarin rêza qadan biguherînin, û ji ber vê yekê "bi gelemperî" (pg_total_relation_size) ...

Li ser cildên mezin di PostgreSQL de quruşek hilînin
... hê jî li vir xilas 1.5%bêyî ku yek rêzek kodê biguhezîne. Erê, belê!

Li ser cildên mezin di PostgreSQL de quruşek hilînin

Ez bala xwe didim ku vebijarka jorîn ji bo sazkirina zeviyan ne rastiyek e ku ew çêtirîn çêtirîn e. Ji ber ku hûn naxwazin hin blokên zeviyan ji ber sedemên estetîkî "çirînin" - mînakî, cotek (pack, recno), ku ji bo vê tabloyê PK ye.

Bi gelemperî, destnîşankirina rêza "kêmtirîn" a zeviyan karekî "hêza hov" pir hêsan e. Ji ber vê yekê, hûn dikarin ji daneyên xwe ji ya me hîn çêtir encamên xwe bistînin - wê biceribînin!

Source: www.habr.com

Add a comment