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, анда чыныгы жазуу ишке ашат негизги столго жана анын ПКга гана эмес, ошондой эле ТОСТ жана анын ПК.

TOAST таасирин азайтуу

Бирок биздин рекорддорубуздун көбү дагы деле чоң эмес, 8KB туура келиши керек - Ушуга кантип акча үнөмдөй алам?..

Бул жерде атрибут жардамга келет STORAGE столдун тилкесинде:

  • УЗАРТЫЛДЫ кысуу жана өзүнчө сактоо мүмкүнчүлүгүн берет. Бул стандарттуу опция көпчүлүк TOAST ылайык келген маалымат түрлөрү үчүн. Ал алгач кысуу аракетин жасайт, андан кийин сап дагы деле өтө чоң болсо, аны үстөлдүн сыртында сактайт.
  • НЕГИЗГИ кысууга мүмкүндүк берет, бирок өзүнчө сактоого болбойт. (Чындыгында, өзүнчө сактоо дагы эле ушундай тилкелер үчүн аткарылат, бирок бир гана акыркы чара катары, сапты баракка туура келгидей кылып кичирейтүүнүн башка жолу жок болгондо.)

Чынында, бул бизге текст үчүн эмне керек - аны мүмкүн болушунча кысып коюңуз, эгер ал такыр туура келбесе, ТОСТТКА салыңыз. Бул түздөн-түз учуп, бир буйрук менен жасалышы мүмкүн:

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 эсе аз жаза баштады, ал дискти гана эмес, процессорду да түшүргөн:

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 пайызды түзөт! Бирок, балким, бул кандайдыр бир жол менен CPU таасир эткен?

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 байт Smallint кийинки талаага чейин жана ал акыркы болгондо, эч нерсе жок жана тегиздөөнүн кереги жок.

Теориялык жактан алганда, баары жакшы жана сиз каалагандай талааларды иретке келтире аласыз. Келгиле, аны күнүмдүк бөлүмү 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 болуп саналат.

Жалпысынан алганда, талаалардын "минималдуу" жайгашуусун аныктоо өтө жөнөкөй "кара күч" милдети болуп саналат. Ошондуктан, сиз өз маалыматтарыңыздан биздикине караганда дагы жакшы натыйжаларды ала аласыз - аракет кылыңыз!

Source: www.habr.com

Комментарий кошуу