Настављајући тему снимања великих токова података покренуту од
причаћемо о ТОАСТ подешавања и поравнање података. „У просеку“, ове методе неће уштедети превише ресурса, али без модификације кода апликације уопште.
Међутим, наше искуство се показало веома продуктивним у том погледу, пошто је складиштење скоро сваког праћења по својој природи углавном само за додавање у погледу снимљених података. А ако се питате како да научите базу података да уместо тога пише на диск КСНУМКСМБ / с упола мање - молим под кат.
Мале тајне великих података
По профилу посла
И од
Погледајмо структуру једне од табела у коју уписујемо „сирове“ податке – то јест, ево оригиналног текста из уноса у дневник:
CREATE TABLE rawdata_orig(
pack -- PK
uuid NOT NULL
, recno -- PK
smallint NOT NULL
, dt -- ключ секции
date
, data -- самое главное
text
, PRIMARY KEY(pack, recno)
);
Типичан знак (већ подељен, наравно, па је ово шаблон одељка), где је најважнији текст. Понекад прилично обиман.
Подсетимо се да „физичка“ величина једног записа у ПГ не може да заузима више од једне странице података, али „логичка“ величина је сасвим друга ствар. Да бисте записали волуметријску вредност (варцхар/тект/битеа) у поље, користите
ПостгреСКЛ користи фиксну величину странице (обично 8 КБ) и не дозвољава да се торке простиру на више страница. Због тога је немогуће директно ускладиштити веома велике вредности поља. Да би се превазишло ово ограничење, велике вредности поља се компримују и/или деле на више физичких линија. Ово се дешава непримећено од стране корисника и има мали утицај на већину серверског кода. Овај метод је познат као ТОАСТ...
У ствари, за сваку табелу са "потенцијално великим" пољима, аутоматски
TOAST(
chunk_id
integer
, chunk_seq
integer
, chunk_data
bytea
, PRIMARY KEY(chunk_id, chunk_seq)
);
То јест, ако морамо да напишемо стринг са „великом“ вредношћу data
, тада ће доћи до правог снимања не само на главни сто и његов ПК, већ и на ТОАСТ и његов ПК.
Смањење утицаја ТОАСТ-а
Али већина наших рекорда још увек није тако велика, требало би да стане у 8КБ - Како да уштедим на овоме?..
Ту нам атрибут долази у помоћ STORAGE
- ЕКСТЕНДЕД омогућава и компресију и одвојено складиштење. Ово стандардна опција за већину типова података усаглашених са ТОАСТ-ом. Прво покушава да изврши компресију, а затим га складишти ван табеле ако је ред и даље превелик.
- ГЛАВНИ омогућава компресију, али не и одвојено складиштење. (У ствари, одвојено складиштење ће се и даље обављати за такве колоне, али само као последње средство, када не постоји други начин да се стринг смањи тако да стане на страницу.)
У ствари, то је управо оно што нам треба за текст - стисните га што је више могуће, а ако уопште не стане, ставите га у ТОАСТ. Ово се може урадити директно у ходу, једном командом:
ALTER TABLE rawdata_orig ALTER COLUMN data SET STORAGE MAIN;
Како проценити ефекат
Пошто се ток података мења сваког дана, не можемо поредити апсолутне бројеве, већ релативне мањи удео Записали смо то у ТОАСТ - тим боље. Али овде постоји опасност – што је већи „физички” обим сваког појединачног записа, индекс постаје „шири”, јер морамо да покријемо више страница података.
Одељак пре промена:
heap = 37GB (39%)
TOAST = 54GB (57%)
PK = 4GB ( 4%)
Одељак после промена:
heap = 37GB (67%)
TOAST = 16GB (29%)
PK = 2GB ( 4%)
У ствари, ми почео да пише у ТОАСТ 2 пута ређе, који је испразнио не само диск, већ и ЦПУ:
Приметићу да смо постали мањи и у „читању“ диска, а не само у „писању“ – пошто приликом уметања записа у табелу, морамо и да „читамо“ део стабла сваког индекса да бисмо одредили његов будући положај у њима.
Ко може добро да живи на ПостгреСКЛ 11
Након ажурирања на ПГ11, одлучили смо да наставимо са „подешавањем“ ТОАСТ-а и приметили смо да је од ове верзије параметар постао доступан за подешавање toast_tuple_target
Код за обраду ТОАСТ се покреће само када је вредност реда која се чува у табели већа од ТОАСТ_ТУПЛЕ_ТХРЕСХОЛД бајтова (обично 2 КБ). ТОАСТ код ће компримовати и/или преместити вредности поља из табеле све док вредност реда не постане мања од ТОАСТ_ТУПЛЕ_ТАРГЕТ бајтова (променљива вредност, такође обично 2 КБ) или се величина не може смањити.
Одлучили смо да су подаци које обично имамо или „веома кратки“ или „веома дуги“, па смо одлучили да се ограничимо на минималну могућу вредност:
ALTER TABLE rawplan_orig SET (toast_tuple_target = 128);
Да видимо како су нова подешавања утицала на учитавање диска након реконфигурације:
Није лоше! Просек ред до диска се смањио отприлике 1.5 пута, а диск је „заузет“ 20 процената! Али можда је то некако утицало на ЦПУ?
Барем није било горе. Иако је тешко проценити да ли чак и такве количине још увек не могу да повећају просечно оптерећење ЦПУ-а 5%.
Променом места појмова мења се збир...!
Као што знате, један пени штеди рубљу, а са нашим количинама складиштења ради се о томе 10ТБ/месец чак и мала оптимизација може дати добар профит. Стога смо обратили пажњу на физичку структуру наших података – како тачно „наслагана“ поља унутар записа свака од табела.
Јер због
Многе архитектуре обезбеђују поравнање података на границама машинских речи. На пример, на 32-битном к86 систему, цели бројеви (тип целог броја, 4 бајта) ће бити поравнати на граници речи од 4 бајта, као и бројеви са помичним зарезом двоструке прецизности (покретни зарез двоструке прецизности, 8 бајтова). А на 64-битном систему, двоструке вредности ће бити усклађене са границама речи од 8 бајта. Ово је још један разлог за некомпатибилност.
Због поравнања, величина реда табеле зависи од редоследа поља. Обично овај ефекат није веома приметан, али у неким случајевима може довести до значајног повећања величине. На пример, ако помешате цхар(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)
, што је ПК за ову табелу.
Генерално, одређивање „минималног“ распореда поља је прилично једноставан задатак „грубе силе“. Стога, можете добити још боље резултате од ваших података од наших - испробајте!
Извор: ввв.хабр.цом