PostgreSQLде EAVди JSONB менен алмаштыруу

TL; DR: JSONB сурамдардын аткарылышын жоготпостон, маалымат базасынын схемасын иштеп чыгууну абдан жөнөкөйлөтө алат.

тааныштыруу

Келгиле, реляциялык маалыматтар базасын (маалыматтар базасын) дүйнөдөгү эң эски колдонуу учурларынын бирине классикалык мисал келтирели: бизде объект бар жана биз бул объекттин айрым касиеттерин (атрибуттарын) сактообуз керек. Бирок бардык инстанциялар бирдей касиеттерге ээ боло бербейт жана келечекте дагы көп касиеттер кошулушу мүмкүн.

Бул көйгөйдү чечүүнүн эң оңой жолу - ар бир касиеттин мааниси үчүн маалымат базасынын таблицасында тилке түзүү жана жөн гана белгилүү бир объекттин инстанциясы үчүн керектүүлөрдү толтуруу. Абдан жакшы! Маселе чечилди... таблицаңызда миллиондогон жазуулар камтылганга чейин жана сиз жаңы жазууну кошушуңуз керек болгонго чейин.

EAV үлгүсүн карап көрөлү (Entity-Atribut-Value), бул абдан көп кездешет. Бир таблицада объекттер (жазуулар), экинчи таблицада касиеттердин аталыштары (атрибуттар), үчүнчү таблицада объектилер алардын атрибуттары менен байланышат жана учурдагы объект үчүн ошол атрибуттардын мааниси камтылган. Бул сизге ар кандай объекттер үчүн касиеттердин ар кандай топтомуна ээ болуу мүмкүнчүлүгүн берет, ошондой эле маалымат базасынын түзүмүн өзгөртпөстөн тез арада касиеттерди кошууга мүмкүнчүлүк берет.

Бирок, EVA ыкмасынын терс жактары болбосо, мен бул постту жазбайт элем. Ошентип, мисалы, ар биринде 1 атрибутка ээ болгон бир же бир нече объектти алуу үчүн, суроодо 2 кошулуу талап кылынат: биринчиси - атрибут таблицасы менен кошулуу, экинчиси - баалуулуктар таблицасы менен бириктирүү. Эгерде объектте 2 атрибут болсо, анда 4 кошулуу керек! Кошумчалай кетсек, бардык атрибуттар адатта саптар катары сакталат, бул натыйжа үчүн да, WHERE пункту үчүн да типти кастингге алып келет. Эгерде сиз көп суроо жазсаңыз, анда бул ресурстарды пайдалануу жагынан абдан ысырапкорчулук.

Бул ачык-айкын кемчиликтерге карабастан, EAV көптөн бери көйгөйлөрдүн бул түрлөрүн чечүү үчүн колдонулат. Бул сөзсүз түрдө кемчиликтер болгон, жана жөн гана жакшы альтернатива жок болчу.
Бирок кийин PostgreSQLде жаңы "технология" пайда болду...

PostgreSQL 9.4 менен баштап, JSON экилик берилиштерин сактоо үчүн JSONB маалымат түрү кошулган. JSON-ну бул форматта сактоо кадимки JSON текстине караганда бир аз көбүрөөк мейкиндикти жана убакытты талап кылса да, андагы операцияларды аткаруу алда канча ылдамыраак. JSONB ошондой эле индекстөөнү колдойт, бул суроону тезирээк кылат.

JSONB берилиштер түрү бизге бир гана JSONB тилкесин кошуу менен, EAV үлгүсүн алмаштырууга мүмкүндүк берет, бул базанын дизайнын абдан жөнөкөйлөтөт. Бирок көптөр мунун түшүмдүүлүктүн төмөндөшү менен коштолушу керектигин айтышууда... Ошол себептен бул макаланы жаздым.

Сыноо базасын түзүү

Бул салыштыруу үчүн мен базаны PostgreSQL 9.5 жаңы орнотулган 80 долларга түздүм. DigitalOcean Ubuntu 14.04 postgresql.conf файлында кээ бир параметрлерди конфигурациялагандан кийин, мен төмөнкүлөрдү иштеттим бул psql аркылуу скрипт. Маалыматтарды EAV түрүндө көрсөтүү үчүн төмөнкү таблицалар түзүлдү:

CREATE TABLE entity ( 
  id           SERIAL PRIMARY KEY, 
  name         TEXT, 
  description  TEXT
);
CREATE TABLE entity_attribute (
  id          SERIAL PRIMARY KEY, 
  name        TEXT
);
CREATE TABLE entity_attribute_value (
  id                  SERIAL PRIMARY KEY, 
  entity_id           INT    REFERENCES entity(id), 
  entity_attribute_id INT    REFERENCES entity_attribute(id), 
  value               TEXT
);

Төмөндө ошол эле маалыматтар сактала турган, бирок JSONB түрүндөгү тилкеде атрибуттары бар таблица бар - касиеттери.

CREATE TABLE entity_jsonb (
  id          SERIAL PRIMARY KEY, 
  name        TEXT, 
  description TEXT,
  properties  JSONB
);

Бир топ жөнөкөй көрүнөт, туурабы? Андан кийин ал объект таблицаларына кошулду (жак & entity_jsonb) 10 миллион жазуулар, ошого жараша таблица EAV үлгүсүн жана JSONB тилкеси менен мамилени колдонуу менен ошол эле маалыматтар менен толтурулган - entity_jsonb.properties. Ошентип, биз касиеттердин бардык топтому арасында бир нече ар кандай маалымат түрлөрүн алдык. Мисал маалыматтар:

{
  id:          1
  name:        "Entity1"
  description: "Test entity no. 1"
  properties:  {
    color:        "red"
    lenght:       120
    width:        3.1882420
    hassomething: true
    country:      "Belgium"
  } 
}

Ошентип, азыр бизде эки вариант үчүн бирдей маалыматтар бар. Жумушта ишке ашырууларды салыштырып баштайлы!

Дизайныңызды жөнөкөйлөтүңүз

Буга чейин маалыматтар базасынын дизайны абдан жөнөкөйлөштүрүлгөнү айтылган: EAV үчүн үч таблицаны колдонуунун ордуна касиеттер үчүн JSONB тилкесин колдонуу менен бир таблица. Бирок бул суроо-талаптарда кандайча чагылдырылат? Бир объект касиетин жаңыртуу төмөнкүдөй көрүнөт:

-- EAV
UPDATE entity_attribute_value 
SET value = 'blue' 
WHERE entity_attribute_id = 1 
  AND entity_id = 120;

-- JSONB
UPDATE entity_jsonb 
SET properties = jsonb_set(properties, '{"color"}', '"blue"') 
WHERE id = 120;

Көрүнүп тургандай, акыркы өтүнүч жөнөкөй көрүнбөйт. JSONB объектиндеги касиеттин маанисин жаңыртуу үчүн биз функцияны колдонушубуз керек jsonb_set(), жана биздин жаңы маанини JSONB объекти катары өткөрүү керек. Бирок, алдын ала кандайдыр бир идентификаторду билишибиз керек эмес. EAV мисалын карап, жаңыртууну ишке ашыруу үчүн entity_id жана entity_attribute_id экөөнү тең билишибиз керек. Эгер сиз JSONB тилкесиндеги касиетти объекттин аталышынын негизинде жаңырткыңыз келсе, анда анын баары бир жөнөкөй сапта жасалат.

Эми жаңы түсүнүн негизинде жаңыртылган объектти тандайлы:

-- EAV
SELECT e.name 
FROM entity e 
  INNER JOIN entity_attribute_value eav ON e.id = eav.entity_id
  INNER JOIN entity_attribute ea ON eav.entity_attribute_id = ea.id
WHERE ea.name = 'color' AND eav.value = 'blue';

-- JSONB
SELECT name 
FROM entity_jsonb 
WHERE properties ->> 'color' = 'blue';

Менимче, биз экинчиси кыскараак (кошулбайбыз!), демек, окула тургандыгы менен макул боло алабыз. JSONB бул жерде утат! JSONB объектинен текст мааниси катары түстү алуу үчүн JSON ->> операторун колдонобуз. JSONB моделинде @> операторунун жардамы менен ошол эле натыйжага жетүүнүн экинчи жолу бар:

-- JSONB 
SELECT name 
FROM entity_jsonb 
WHERE properties @> '{"color": "blue"}';

Бул бир аз татаалыраак: биз анын касиеттери тилкесиндеги JSON объектисинде @> операторунун оң жагында жайгашкан объект бар же жок экенин текшеребиз. Окууга азыраак, жемиштүү (төмөндө караңыз).

Келиңиз, бир эле учурда бир нече касиетти тандоо керек болгондо JSONB колдонууну ого бетер жеңилдетели. Бул жерде JSONB мамилеси чындап эле ишке ашат: биз жөн гана кошулмаларды талап кылбастан, натыйжалар топтомубузда кошумча мамычалар катары касиеттерди тандайбыз:

-- JSONB 
SELECT name
  , properties ->> 'color'
  , properties ->> 'country'
FROM entity_jsonb 
WHERE id = 120;

EAV менен сизге сурагыңыз келген ар бир мүлк үчүн 2 кошулуу керек болот. Менин оюмча, жогорудагы суроо-талаптар базаны долбоорлоодо чоң жөнөкөйлөштүрүүнү көрсөтүп турат. JSONBге суроо жазуунун көбүрөөк мисалдарын караңыз бул пост.
Эми аткаруу жөнүндө сөз кылууга убакыт келди.

кирешелүүлүк

Мен колдонгон натыйжалуулугун салыштыруу ТҮШҮНДҮРҮҢҮЗ АНАЛИЗ суроо-талаптарда, аткаруу убактысын эсептөө үчүн. Ар бир суроо жок дегенде үч жолу аткарылды, анткени суроо пландоочу биринчи жолу көбүрөөк убакытты талап кылат. Адегенде мен эч кандай индекссиз сурамдарды иштеттим. Албетте, бул JSONBнин артыкчылыгы болчу, анткени EAV үчүн талап кылынган кошулмалар индекстерди колдоно албайт (чет элдик ачкыч талаалары индекстелбеген). Андан кийин мен EAV маанилер таблицасынын 2 чет өлкөлүк ачкыч тилкесинде индексти, ошондой эле индексти түздүм GIN JSONB тилкеси үчүн.

Маалыматтарды жаңыртуу убакыт боюнча төмөнкү натыйжаларды көрсөттү (мс менен). шкала логарифмдик экенин белгилей кетүү керек:

PostgreSQLде EAVди JSONB менен алмаштыруу

Жогоруда айтылган себептерден улам индекстерди колдонбосоңуз, JSONB бир топ (> 50000-x) EAVге караганда ылдамыраак экенин көрүп жатабыз. Мамычаларды негизги ачкычтар менен индекстегенде, айырма дээрлик жок болот, бирок JSONB дагы эле EAVге караганда 1,3 эсе тезирээк. JSONB тилкесиндеги индекстин бул жерде эч кандай таасири жок экенин эске алыңыз, анткени биз баалоо критерийлеринде мүлк тилкесин колдонбойбуз.

Мүлктүн наркына негизделген маалыматтарды тандоо үчүн, биз төмөнкү натыйжаларды алабыз (нормалдуу шкала):

PostgreSQLде EAVди JSONB менен алмаштыруу

JSONB кайра индекстери жок EAVге караганда тезирээк иштегенин байкасаңыз болот, бирок EAV индекстери бар болгондо, ал дагы эле JSONBге караганда ылдамыраак иштейт. Бирок кийин мен JSONB сурамдары үчүн убакыт бирдей болгонун көрдүм, бул мени GIN индекстери иштебей тургандыгына түрткү болду. Кыязы, сиз GIN индексин толтурулган касиеттери бар тилкеде колдонгонуңузда, ал @> кошуу операторун колдонгондо гана күчүнө кирет. Мен муну жаңы тестте колдондум жана ал убакытка чоң таасирин тийгизди: болгону 0,153 мс! Бул EAVден 15000 25000 эсе тез жана ->> операторунан XNUMX XNUMX эсе ылдам.

Мен бул жетиштүү тез болду деп ойлойм!

Берилиштер базасынын таблицасынын өлчөмү

Келгиле, эки ыкманын үстөл өлчөмүн салыштырып көрөлү. Psqlде биз команданын жардамы менен бардык таблицалардын жана индекстердин өлчөмүн көрсөтө алабыз dti+

PostgreSQLде EAVди JSONB менен алмаштыруу

EAV ыкмасы үчүн столдун өлчөмдөрү болжол менен 3068 МБ жана индекстери 3427 МБга чейин, жалпысынан 6,43 ГБ. JSONB ыкмасы үстөл үчүн 1817 МБ жана индекстер үчүн 318 МБ колдонот, бул 2,08 ГБ. Бул 3 эсе аз болуп чыкты! Бул факт мени бир аз таң калтырды, анткени биз ар бир JSONB объектисинде менчик аталыштарын сактайбыз.

Бирок, ошентсе да, сандар өздөрү үчүн сүйлөйт: EAVде биз ар бир атрибуттун маанисине 2 бүтүн тышкы ачкычты сактайбыз, натыйжада 8 байт кошумча маалымат пайда болот. Кошумчалай кетсек, EAV бардык менчик баалуулуктарын текст катары сактайт, ал эми JSONB мүмкүн болсо, ички сандык жана логикалык маанилерди колдонот, натыйжада азыраак изи болот.

натыйжалары

Жалпысынан, менимче, объекттин касиеттерин JSONB форматында сактоо сиздин маалымат базасын иштеп чыгууну жана тейлөөнү бир топ жеңилдетет. Эгер сиз көп сурамдарды аткарып жатсаңыз, анда бардыгын субъект менен бир таблицада сактоо чындыгында натыйжалуураак иштейт. Ал эми бул маалыматтардын ортосундагы өз ара аракеттенүүнү жөнөкөйлөтүп жатканы буга чейин эле плюс, бирок натыйжада маалымат базасы көлөмү боюнча 3 эсе аз.

Ошондой эле, жүргүзүлгөн сыноолордун негизинде, биз аткаруу жоготуулар абдан аз деп тыянак чыгарууга болот. Кээ бир учурларда, JSONB EAVден да тезирээк, аны андан да жакшыраак кылат. Бирок, бул эталон, албетте, бардык аспектилерди камтыбайт (мисалы, абдан көп сандагы касиеттерге ээ субъекттер, учурдагы маалыматтардын касиеттеринин санынын олуттуу өсүшү,...), андыктан аларды кантип жакшыртуу боюнча кандайдыр бир сунуштарыңыз болсо. , комментарийге калтырсаныз болот!

Source: www.habr.com

DDoS коргоосу, VPS VDS серверлери бар сайттар үчүн ишенимдүү хостинг сатып алыңыз 🔥 DDoS коргоосу, VPS VDS серверлери бар ишенимдүү веб-сайт хостингин сатып алыңыз | ProHoster