Көтерілген үлкен деректер ағындарын жазу тақырыбын жалғастыру
туралы сөйлесеміз TOAST параметрлері және деректерді туралау. «Орташа» бұл әдістер тым көп ресурстарды үнемдемейді, бірақ қолданба кодын мүлде өзгертпейді.
Дегенмен, біздің тәжірибеміз бұл тұрғыда өте нәтижелі болды, өйткені кез келген дерлік мониторинг өзінің табиғаты бойынша сақталады негізінен тек қосымшалар жазылған деректер тұрғысынан. Егер сіз оның орнына дерекқорды дискіге жазуды қалай үйретуге болатынын білгіңіз келсе 200MB / с жартысы - мысық астында өтінемін.
Үлкен деректердің кішкентай құпиялары
Жұмыс профилі бойынша
Және содан бері
Біз «шикі» деректерді жазатын кестелердің бірінің құрылымын қарастырайық, яғни журнал жазбасының түпнұсқа мәтіні:
CREATE TABLE rawdata_orig(
pack -- PK
uuid NOT NULL
, recno -- PK
smallint NOT NULL
, dt -- ключ секции
date
, data -- самое главное
text
, PRIMARY KEY(pack, recno)
);
Типтік белгі (әлбетте, қазірдің өзінде бөлінген, сондықтан бұл бөлім үлгісі), мұнда ең маңыздысы - мәтін. Кейде өте көлемді.
Еске салайық, PG-дегі бір жазбаның «физикалық» өлшемі деректердің бір бетінен артық ала алмайды, бірақ «логикалық» өлшем мүлдем басқа мәселе. Өріске көлемдік мәнді (varchar/мәтін/байт) жазу үшін пайдаланыңыз
PostgreSQL бекітілген бет өлшемін (әдетте 8 КБ) пайдаланады және кортеждер бірнеше бетті қамтуға мүмкіндік бермейді. Сондықтан өте үлкен өріс мәндерін тікелей сақтау мүмкін емес. Бұл шектеуді еңсеру үшін үлкен өріс мәндері қысылады және/немесе бірнеше физикалық сызықтар бойынша бөлінеді. Бұл пайдаланушы байқамай қалады және көптеген сервер кодтарына аз әсер етеді. Бұл әдіс ТОАСТ деп аталады...
Шын мәнінде, «ықтимал үлкен» өрістері бар әрбір кесте үшін автоматты түрде
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 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);
Қайта конфигурациялаудан кейін жаңа параметрлер дискінің жүктелуіне қалай әсер еткенін көрейік:
Жаман емес! Орташа дискіге кезек азайды шамамен 1.5 есе, ал диск «бос емес» 20 пайыз! Бірақ бұл процессорға қандай да бір түрде әсер еткен шығар?
Кем дегенде, одан да жаман болған жоқ. Дегенмен, тіпті мұндай көлемдер әлі де орташа 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
) ондағы жазбалар саны бойынша - яғни аламыз нақты сақталған жазбаның орташа өлшемі:
Минус 6% көлем, Тамаша!
Бірақ бәрі, әрине, соншалықты қызғылт емес - ақыр соңында, индекстерде өрістердің ретін өзгерте алмаймыз, сондықтан «жалпы» (pg_total_relation_size
) ...
...әлі де осында 1.5% үнемделгенкодтың бір жолын өзгертпей. Иә Иә!
Өрістерді орналастырудың жоғарыдағы нұсқасы оның ең оңтайлы екендігі фактісі емес екенін ескеремін. Сіз эстетикалық себептермен өрістердің кейбір блоктарын «жыртқыңыз» келмейтіндіктен, мысалы, жұп (pack, recno)
, бұл кесте үшін PK болып табылады.
Жалпы, кен орындарының «минималды» орналасуын анықтау өте қарапайым «қатал күш» міндеті болып табылады. Сондықтан сіз өзіңіздің деректеріңізден біздікінен де жақсы нәтиже ала аласыз - көріңіз!
Ақпарат көзі: www.habr.com