TL; DR: Gall JSONB symleiddio datblygiad sgema cronfa ddata yn fawr heb aberthu perfformiad ymholiad.
Cyflwyniad
Gadewch i ni roi enghraifft glasurol o un o'r achosion defnydd hynaf yn ôl pob tebyg ym myd cronfa ddata berthynol (cronfa ddata): mae gennym endid, ac mae angen i ni arbed rhai eiddo (priodoleddau) yr endid hwn. Ond efallai na fydd gan bob achos yr un set o eiddo, ac efallai y bydd mwy o eiddo yn cael eu hychwanegu yn y dyfodol.
Y ffordd hawsaf o ddatrys y broblem hon yw creu colofn yn nhabl y gronfa ddata ar gyfer pob gwerth eiddo, a llenwi'r rhai sydd eu hangen ar gyfer enghraifft endid penodol. Gwych! Problem wedi'i datrys... nes bod eich tabl yn cynnwys miliynau o gofnodion a bod angen i chi ychwanegu cofnod newydd.
Ystyriwch y patrwm EAV (
Fodd bynnag, ni fyddwn yn ysgrifennu'r post hwn pe na bai rhai anfanteision i'r dull EVA. Felly, er enghraifft, i gael un neu fwy o endidau sydd ag 1 priodoledd yr un, mae angen 2 uniad yn yr ymholiad: mae'r cyntaf yn uniad â'r tabl priodoleddau, mae'r ail yn uniad â'r tabl gwerthoedd. Os oes gan endid 2 nodwedd, yna mae angen 4 uniad! Yn ogystal, mae'r holl briodoleddau fel arfer yn cael eu storio fel llinynnau, sy'n arwain at gastio math ar gyfer y canlyniad a'r cymal LLE. Os byddwch yn ysgrifennu llawer o ymholiadau, yna mae hyn yn eithaf gwastraffus o ran defnyddio adnoddau.
Er gwaethaf y diffygion amlwg hyn, mae EAV wedi cael ei ddefnyddio ers tro i ddatrys y mathau hyn o broblemau. Roedd y rhain yn ddiffygion anochel, ac yn syml iawn nid oedd dewis arall gwell.
Ond yna ymddangosodd “technoleg” newydd yn PostgreSQL...
Gan ddechrau gyda PostgreSQL 9.4, ychwanegwyd y math data JSONB i storio data deuaidd JSON. Er bod storio JSON yn y fformat hwn fel arfer yn cymryd ychydig mwy o le ac amser na JSON testun plaen, mae perfformio gweithrediadau arno yn llawer cyflymach. Mae JSONB hefyd yn cefnogi mynegeio, sy'n gwneud ymholiadau hyd yn oed yn gyflymach.
Mae'r math o ddata JSONB yn caniatáu inni ddisodli'r patrwm EAV beichus trwy ychwanegu dim ond un golofn JSONB at ein tabl endid, gan symleiddio dyluniad cronfa ddata yn fawr. Ond mae llawer yn dadlau y dylai hyn gyd-fynd â gostyngiad mewn cynhyrchiant... Dyna pam ysgrifennais yr erthygl hon.
Sefydlu cronfa ddata prawf
Ar gyfer y gymhariaeth hon, creais y gronfa ddata ar osodiad newydd o PostgreSQL 9.5 ar yr adeilad $80
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
);
Isod mae tabl lle bydd yr un data yn cael ei storio, ond gyda phriodoleddau mewn colofn o fath JSONB - eiddo.
CREATE TABLE entity_jsonb (
id SERIAL PRIMARY KEY,
name TEXT,
description TEXT,
properties JSONB
);
Edrych yn llawer symlach, yn tydi? Yna cafodd ei ychwanegu at y tablau endid (endid & endid_jsonb) 10 miliwn o gofnodion, ac yn unol â hynny, llenwyd y tabl gyda'r un data gan ddefnyddio'r patrwm EAV a'r dull gyda cholofn JSONB - endid_jsonb.eiddo. Felly, cawsom sawl math gwahanol o ddata ymhlith y set gyfan o eiddo. Data enghreifftiol:
{
id: 1
name: "Entity1"
description: "Test entity no. 1"
properties: {
color: "red"
lenght: 120
width: 3.1882420
hassomething: true
country: "Belgium"
}
}
Felly nawr mae gennym yr un data ar gyfer y ddau opsiwn. Gadewch i ni ddechrau cymharu gweithrediadau yn y gwaith!
Symleiddiwch eich dyluniad
Dywedwyd yn flaenorol bod dyluniad y gronfa ddata wedi'i symleiddio'n fawr: un tabl, trwy ddefnyddio colofn JSONB ar gyfer eiddo, yn lle defnyddio tri thabl ar gyfer EAV. Ond sut mae hyn yn cael ei adlewyrchu mewn ceisiadau? Mae diweddaru eiddo un endid yn edrych fel hyn:
-- 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;
Fel y gwelwch, nid yw'r cais olaf yn edrych yn symlach. I ddiweddaru gwerth eiddo mewn gwrthrych JSONB mae'n rhaid i ni ddefnyddio'r ffwythiant
Nawr, gadewch i ni ddewis yr endid rydyn ni newydd ei ddiweddaru yn seiliedig ar ei liw newydd:
-- 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';
Rwy'n meddwl y gallwn gytuno bod yr ail un yn fyrrach (dim ymuno!), ac felly'n fwy darllenadwy. JSONB yn ennill yma! Rydym yn defnyddio'r gweithredwr JSON ->> i gael y lliw fel gwerth testun o wrthrych JSONB. Mae yna hefyd ail ffordd i gyflawni'r un canlyniad ym model JSONB gan ddefnyddio'r gweithredwr @>:
-- JSONB
SELECT name
FROM entity_jsonb
WHERE properties @> '{"color": "blue"}';
Mae hyn ychydig yn fwy cymhleth: rydym yn gwirio i weld a yw'r gwrthrych JSON yn ei golofn eiddo yn cynnwys gwrthrych sydd i'r dde i'r gweithredwr @>. Llai darllenadwy, mwy cynhyrchiol (gweler isod).
Gadewch i ni wneud defnyddio JSONB hyd yn oed yn haws pan fydd angen i chi ddewis eiddo lluosog ar unwaith. Dyma lle mae dull JSONB yn dod i mewn mewn gwirionedd: yn syml, rydyn ni'n dewis eiddo fel colofnau ychwanegol yn ein set canlyniadau heb fod angen uniadau:
-- JSONB
SELECT name
, properties ->> 'color'
, properties ->> 'country'
FROM entity_jsonb
WHERE id = 120;
Gydag EAV bydd angen 2 uniad arnoch ar gyfer pob eiddo rydych am ei holi. Yn fy marn i, mae'r ymholiadau uchod yn dangos symleiddio mawr mewn dylunio cronfa ddata. Gweler mwy o enghreifftiau o sut i ysgrifennu ymholiadau JSONB, hefyd yn
Nawr mae'n bryd siarad am berfformiad.
Cynhyrchiant
I gymharu perfformiad defnyddiais
Dangosodd y diweddariad data y canlyniadau canlynol o ran amser (mewn ms). Sylwch fod y raddfa yn logarithmig:
Gwelwn fod JSONB yn llawer (> 50000-x) yn gyflymach nag EAV os nad ydych yn defnyddio mynegeion, am y rheswm a nodir uchod. Pan fyddwn yn mynegeio colofnau ag allweddi cynradd, mae'r gwahaniaeth bron yn diflannu, ond mae JSONB yn dal i fod 1,3 gwaith yn gyflymach nag EAV. Sylwch nad yw'r mynegai ar y golofn JSONB yn cael unrhyw effaith yma gan nad ydym yn defnyddio'r golofn eiddo yn y meini prawf gwerthuso.
Ar gyfer dewis data yn seiliedig ar werth eiddo, rydym yn cael y canlyniadau canlynol (graddfa arferol):
Gallwch sylwi bod JSONB eto'n gweithio'n gyflymach nag EAV heb fynegeion, ond pan fydd EAV gyda mynegeion, mae'n dal i weithio'n gyflymach na JSONB. Ond yna gwelais fod yr amseroedd ar gyfer ymholiadau JSONB yr un fath, fe ysgogodd hyn fi at y ffaith nad yw mynegeion GIN yn gweithio. Mae'n debyg pan fyddwch chi'n defnyddio mynegai GIN ar golofn â phriodweddau poblog, dim ond wrth ddefnyddio'r gweithredwr cynnwys @> y mae'n dod i rym. Defnyddiais hwn mewn prawf newydd a chafodd effaith enfawr ar yr amser: dim ond 0,153ms! Mae hyn 15000 gwaith yn gyflymach nag EAV a 25000 gwaith yn gyflymach na'r gweithredwr ->>.
Rwy'n meddwl ei fod yn ddigon cyflym!
Maint tabl cronfa ddata
Gadewch i ni gymharu maint y tablau ar gyfer y ddau ddull. Yn psql gallwn ddangos maint yr holl dablau a mynegeion gan ddefnyddio'r gorchymyn dti+
Ar gyfer y dull EAV, mae meintiau tablau tua 3068 MB a mynegeion hyd at 3427 MB ar gyfer cyfanswm o 6,43 GB. Mae dull JSONB yn defnyddio 1817 MB ar gyfer y tabl a 318 MB ar gyfer y mynegeion, sef 2,08 GB. Mae'n troi allan 3 gwaith yn llai! Roedd y ffaith hon yn fy synnu ychydig oherwydd ein bod yn storio enwau eiddo ym mhob gwrthrych JSONB.
Ond o hyd, mae'r niferoedd yn siarad drostynt eu hunain: yn EAV rydym yn storio 2 allwedd gyfanrif tramor fesul gwerth priodoledd, gan arwain at 8 beit o ddata ychwanegol. Yn ogystal, mae EAV yn storio pob gwerth eiddo fel testun, tra bydd JSONB yn defnyddio gwerthoedd rhifol a boolaidd yn fewnol lle bo modd, gan arwain at ôl troed llai.
Canlyniadau
Ar y cyfan, rwy'n credu y gall arbed eiddo endid ar ffurf JSONB ei gwneud hi'n llawer haws dylunio a chynnal eich cronfa ddata. Os ydych chi'n rhedeg llawer o ymholiadau, yna bydd cadw popeth yn yr un tabl â'r endid yn gweithio'n fwy effeithlon mewn gwirionedd. Ac mae'r ffaith bod hyn yn symleiddio'r rhyngweithio rhwng data eisoes yn fantais, ond mae'r gronfa ddata sy'n deillio o hynny 3 gwaith yn llai o ran cyfaint.
Hefyd, yn seiliedig ar y profion a gyflawnwyd, gallwn ddod i'r casgliad bod y colledion perfformiad yn ddibwys iawn. Mewn rhai achosion, mae JSONB hyd yn oed yn gyflymach nag EAV, gan ei wneud hyd yn oed yn well. Fodd bynnag, wrth gwrs, nid yw'r meincnod hwn yn cwmpasu pob agwedd (e.e. endidau sydd â nifer fawr iawn o eiddo, cynnydd sylweddol yn nifer eiddo'r data presennol,...), felly os oes gennych unrhyw awgrymiadau ar sut i'w gwella , mae croeso i chi adael yn y sylwadau!
Ffynhonnell: hab.com