PostgreSQL-де үлкен көлемдерде бір тиын үнемдеңіз

Көтерілген үлкен деректер ағындарын жазу тақырыбын жалғастыру бөлу туралы алдыңғы мақала, бұл жерде біз сіз жасай алатын жолдарды қарастырамыз сақталған «физикалық» өлшемін азайтыңыз PostgreSQL және олардың сервер жұмысына әсері.

туралы сөйлесеміз TOAST параметрлері және деректерді туралау. «Орташа» бұл әдістер тым көп ресурстарды үнемдемейді, бірақ қолданба кодын мүлде өзгертпейді.

PostgreSQL-де үлкен көлемдерде бір тиын үнемдеңіз
Дегенмен, біздің тәжірибеміз бұл тұрғыда өте нәтижелі болды, өйткені кез келген дерлік мониторинг өзінің табиғаты бойынша сақталады негізінен тек қосымшалар жазылған деректер тұрғысынан. Егер сіз оның орнына дерекқорды дискіге жазуды қалай үйретуге болатынын білгіңіз келсе 200MB / с жартысы - мысық астында өтінемін.

Үлкен деректердің кішкентай құпиялары

Жұмыс профилі бойынша біздің қызметіміз, олар оған ұялардан үнемі ұшады мәтіндік пакеттер.

Және содан бері VLSI кешеніоның дерекқоры біз бақылайтын күрделі деректер құрылымдары бар көп құрамды өнім, содан кейін сұраулар максималды өнімділік үшін әбден осылай болып шығады Күрделі алгоритмдік логикасы бар «көп томдық».. Осылайша, бізге келетін журналдағы сұраудың әрбір жеке данасы немесе нәтижесінде орындалатын жоспардың көлемі «орташа» өте үлкен болып шығады.

Біз «шикі» деректерді жазатын кестелердің бірінің құрылымын қарастырайық, яғни журнал жазбасының түпнұсқа мәтіні:

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

Типтік белгі (әлбетте, қазірдің өзінде бөлінген, сондықтан бұл бөлім үлгісі), мұнда ең маңыздысы - мәтін. Кейде өте көлемді.

Еске салайық, PG-дегі бір жазбаның «физикалық» өлшемі деректердің бір бетінен артық ала алмайды, бірақ «логикалық» өлшем мүлдем басқа мәселе. Өріске көлемдік мәнді (varchar/мәтін/байт) жазу үшін пайдаланыңыз TOAST технологиясы:

PostgreSQL бекітілген бет өлшемін (әдетте 8 КБ) пайдаланады және кортеждер бірнеше бетті қамтуға мүмкіндік бермейді. Сондықтан өте үлкен өріс мәндерін тікелей сақтау мүмкін емес. Бұл шектеуді еңсеру үшін үлкен өріс мәндері қысылады және/немесе бірнеше физикалық сызықтар бойынша бөлінеді. Бұл пайдаланушы байқамай қалады және көптеген сервер кодтарына аз әсер етеді. Бұл әдіс ТОАСТ деп аталады...

Шын мәнінде, «ықтимал үлкен» өрістері бар әрбір кесте үшін автоматты түрде «кесілген» жұптастырылған кесте жасалады 2КБ сегменттердегі әрбір «үлкен» жазба:

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

Яғни, «үлкен» мәні бар жолды жазу керек болса data, содан кейін нақты жазу орын алады тек негізгі үстелге және оның PK-ға ғана емес, сонымен қатар TOAST пен оның PK-ға.

TOAST әсерін азайту

Бірақ біздің рекордтарымыздың көпшілігі әлі де үлкен емес, 8 КБ-ға сәйкес келуі керек - Бұған қалай ақша үнемдей аламын?..

Дәл осы жерде атрибут көмекке келеді STORAGE кесте бағанында:

  • Ұзартылған қысуға да, бөлек сақтауға да мүмкіндік береді. Бұл стандартты опция TOAST үйлесімді деректер түрлерінің көпшілігі үшін. Ол алдымен қысуды орындауға тырысады, содан кейін жол әлі тым үлкен болса, оны кестеден тыс сақтайды.
  • HAND қысуға мүмкіндік береді, бірақ бөлек сақтауға болмайды. (Шын мәнінде, мұндай бағандар үшін бөлек сақтау орындалады, бірақ тек соңғы шара ретінде, жолды бетке сәйкестендіру үшін қысқартудың басқа жолы болмаған кезде.)

Шын мәнінде, бұл бізге мәтін үшін қажет нәрсе - оны мүмкіндігінше қысыңыз, ал егер ол мүлдем сәйкес келмесе, оны ТОАСТ-қа салыңыз. Мұны бір пәрмен арқылы тікелей орындауға болады:

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%)

Шын мәнінде, біз ТОАСТ-қа 2 есе аз жаза бастады, ол тек дискіні ғана емес, сонымен қатар процессорды да түсірді:

PostgreSQL-де үлкен көлемдерде бір тиын үнемдеңіз
PostgreSQL-де үлкен көлемдерде бір тиын үнемдеңіз
Біз дискіні «оқу» кезінде де кішірейгенімізді атап өтейін, тек «жазу» ғана емес, өйткені кестеге жазбаны енгізу кезінде біз оның мәнін анықтау үшін әр индекстің ағашының бір бөлігін «оқуымыз» керек. олардың болашақтағы орны.

PostgreSQL 11-де кім жақсы өмір сүре алады

PG11-ге жаңартқаннан кейін біз TOAST «баптауды» жалғастыруды шештік және осы нұсқадан бастап параметр баптау үшін қолжетімді болғанын байқадық. toast_tuple_target:

TOAST өңдеу коды кестеде сақталатын жол мәні TOAST_TUPLE_THRESHOLD байтынан (әдетте 2 КБ) үлкен болғанда ғана іске қосылады. TOAST коды жолдың мәні TOAST_TUPLE_TARGET байттарынан (айнымалы мән, сонымен қатар әдетте 2 КБ) аз болғанша немесе өлшемді азайту мүмкін болмайынша, өріс мәндерін қысады және/немесе кестеден жылжытады.

Біз әдетте қолымызда бар деректер «өте қысқа» немесе «өте ұзақ» деп шештік, сондықтан біз өзімізді ең төменгі мүмкін мәнмен шектеуді шештік:

ALTER TABLE rawplan_orig SET (toast_tuple_target = 128);

Қайта конфигурациялаудан кейін жаңа параметрлер дискінің жүктелуіне қалай әсер еткенін көрейік:

PostgreSQL-де үлкен көлемдерде бір тиын үнемдеңіз
Жаман емес! Орташа дискіге кезек азайды шамамен 1.5 есе, ал диск «бос емес» 20 пайыз! Бірақ бұл процессорға қандай да бір түрде әсер еткен шығар?

PostgreSQL-де үлкен көлемдерде бір тиын үнемдеңіз
Кем дегенде, одан да жаман болған жоқ. Дегенмен, тіпті мұндай көлемдер әлі де орташа CPU жүктемесін жоғарылата алмайтынын айту қиын 5%.

Терминдердің орындарын ауыстыру арқылы қосынды... өзгереді!

Өздеріңіз білетіндей, бір тиын рубльді үнемдейді, ал біздің сақтау көлемімен бұл шамамен 10TB/ай тіпті кішкене оңтайландыру жақсы пайда бере алады. Сондықтан, біз деректеріміздің физикалық құрылымына назар аудардық - дәл қалай Жазба ішіндегі «қабатталған» өрістер кестелердің әрқайсысы.

Себебі, себебі деректерді теңестіру бұл тікелей алға алынған көлемге әсер етеді:

Көптеген архитектуралар машина сөзінің шекараларында деректерді теңестіруді қамтамасыз етеді. Мысалы, 32 биттік x86 жүйесінде бүтін сандар (бүтін сан түрі, 4 байт) 4 байт сөз шекарасында екі есе дәлдіктегі өзгермелі нүкте сандары (екі дәлдіктегі өзгермелі нүкте, 8 байт) тураланады. Ал 64 биттік жүйеде қос мәндер 8 байт сөз шекараларына тураланады. Бұл сәйкессіздіктің тағы бір себебі.

Туралаудың арқасында кесте жолының өлшемі өрістердің ретіне байланысты. Әдетте бұл әсер өте байқалмайды, бірақ кейбір жағдайларда бұл мөлшердің айтарлықтай өсуіне әкелуі мүмкін. Мысалы, 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 байт кішігірім келесі өріске дейін және ол соңғы болғанда, ештеңе жоқ және туралаудың қажеті жоқ.

Теорияда бәрі жақсы және өрістерді қалауыңызша қайта реттей аласыз. Күнделікті бөлімі 10-15 ГБ-ты алатын кестелердің бірінің мысалын пайдаланып, оны нақты деректер бойынша тексерейік.

Бастапқы құрылымы:

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-де үлкен көлемдерде бір тиын үнемдеңіз
Минус 6% көлем, Тамаша!

Бірақ бәрі, әрине, соншалықты қызғылт емес - ақыр соңында, индекстерде өрістердің ретін өзгерте алмаймыз, сондықтан «жалпы» (pg_total_relation_size) ...

PostgreSQL-де үлкен көлемдерде бір тиын үнемдеңіз
...әлі де осында 1.5% үнемделгенкодтың бір жолын өзгертпей. Иә Иә!

PostgreSQL-де үлкен көлемдерде бір тиын үнемдеңіз

Өрістерді орналастырудың жоғарыдағы нұсқасы оның ең оңтайлы екендігі фактісі емес екенін ескеремін. Сіз эстетикалық себептермен өрістердің кейбір блоктарын «жыртқыңыз» келмейтіндіктен, мысалы, жұп (pack, recno), бұл кесте үшін PK болып табылады.

Жалпы, кен орындарының «минималды» орналасуын анықтау өте қарапайым «қатал күш» міндеті болып табылады. Сондықтан сіз өзіңіздің деректеріңізден біздікінен де жақсы нәтиже ала аласыз - көріңіз!

Ақпарат көзі: www.habr.com

пікір қалдыру