TL;DR: Gall JSONB symleiddio datblygu cynllun cronfa ddata yn fawr heb aberthu perfformiad ymholiadau.
Cyflwyniad
Beth am gymryd enghraifft glasurol, un o'r achosion defnydd hynaf ym myd cronfeydd data perthynol yn ôl pob tebyg: mae gennym endid, ac mae angen i ni storio rhai priodweddau (priodoleddau) yr endid hwn. Ond efallai na fydd gan bob achos yr un set o briodweddau, a gellir ychwanegu mwy o briodweddau yn y dyfodol.
Yr ateb symlaf i'r broblem hon yw creu colofn yn nhabl y gronfa ddata ar gyfer pob gwerth priodwedd a llenwi'r rhai sydd eu hangen ar gyfer enghraifft endid benodol. Gwych! Problem wedi'i datrys... nes bod eich tabl yn cynnwys miliynau o gofnodion ac mae angen i chi ychwanegu cofnod newydd.
Gadewch i ni ystyried y patrwm EAV (), mae'n eithaf cyffredin. Mae un tabl yn cynnwys endidau (cofnodion), mae tabl arall yn cynnwys enwau priodweddau (priodoleddau), ac mae trydydd tabl yn cysylltu endidau â'u priodoleddau ac yn cynnwys gwerthoedd y priodoleddau hyn ar gyfer yr endid cyfredol. Mae hyn yn caniatáu ichi gael gwahanol setiau o briodweddau ar gyfer gwahanol wrthrychau, yn ogystal ag ychwanegu priodweddau ar unwaith, heb newid strwythur y gronfa ddata.
Fodd bynnag, ni fyddwn yn ysgrifennu'r post hwn oni bai am rai anfanteision i'r dull EVA. Er enghraifft, mae adfer un neu fwy o endidau gydag un priodoledd yr un yn gofyn am ddau ymuniad yn yr ymholiad: yr ymuniad cyntaf â'r tabl priodoleddau, yr ail ymuniad â'r tabl gwerthoedd. Os oes gan endid ddau briodoledd, yna mae angen pedwar ymuniad! Ar ben hynny, mae'r holl briodoleddau fel arfer yn cael eu storio fel llinynnau, sy'n arwain at orfodaeth math ar gyfer y canlyniad a'r cymal WHERE. Os ydych chi'n ysgrifennu llawer o ymholiadau, mae hyn yn eithaf gwastraffus o ran defnyddio adnoddau.
Er gwaethaf y diffygion amlwg hyn, mae EAV wedi cael ei ddefnyddio ers amser maith i ddatrys y mathau hyn o broblemau. Roedd y rhain yn ddiffygion anochel, ac nid oedd dewis arall gwell.
Ond yna ymddangosodd “technoleg” newydd yn PostgreSQL…
Gan ddechrau gyda PostgreSQL 9.4, ychwanegwyd y math data JSONB ar gyfer storio data JSON deuaidd. Er bod storio JSON yn y fformat hwn fel arfer yn cymryd ychydig mwy o le ac amser na JSON testun plaen, mae gweithrediadau gydag ef yn llawer cyflymach. Mae JSONB hefyd yn cefnogi mynegeio, gan wneud ymholiadau hyd yn oed yn gyflymach.
Mae'r math data JSONB yn caniatáu inni ddisodli'r patrwm EAV anodd trwy ychwanegu un golofn JSONB yn unig at ein tabl endid, gan symleiddio dyluniad cronfa ddata yn sylweddol. Fodd bynnag, mae llawer yn dadlau bod hyn yn dod ar gost o ran perfformiad… Dyna pam ysgrifennais yr erthygl hon.
Sefydlu cronfa ddata brawf
Ar gyfer y gymhariaeth hon, creais y gronfa ddata ar osodiad ffres o PostgreSQL 9.5 ar yr adeiladwaith $80. Ubuntu 14.04 Ar ôl ffurfweddu rhai paramedrau yn postgresql.conf, rhedais sgript gan ddefnyddio psql. I gyflwyno'r data fel EAV, crëwyd y tablau canlynol:
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 JSONB – eiddo.
CREATE TABLE entity_jsonb (
id SERIAL PRIMARY KEY,
name TEXT,
description TEXT,
properties JSONB
);
Mae'n edrych yn llawer symlach, onid yw? Yna cafodd ei ychwanegu at y tablau endid (endid & endid_jsonb) 10 miliwn o gofnodion, ac yn unol â hynny, roedd y tabl wedi'i lenwi â data union yr un fath lle defnyddiwyd y patrwm EAV a'r dull gyda'r golofn JSONB – endid_jsonb.priodweddauFelly, cawsom sawl math data gwahanol ar draws y set gyfan o briodweddau. 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 ddata union yr un fath ar gyfer y ddau opsiwn. Gadewch i ni ddechrau cymharu'r gweithrediadau mewn bywyd go iawn!
Symleiddio'r dyluniad
Soniwyd yn gynharach fod dyluniad y gronfa ddata wedi'i symleiddio'n sylweddol: un tabl, gan ddefnyddio colofn JSONB ar gyfer priodweddau, yn lle tair tabl ar gyfer EAV. Ond sut mae hyn yn cyfieithu i ymholiadau? Mae diweddaru priodwedd endid sengl 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 gallwch weld, nid yw'r ymholiad olaf yn edrych yn symlach. I ddiweddaru gwerth priodwedd mewn gwrthrych JSONB, rhaid inni ddefnyddio'r ffwythiant , a rhaid iddo basio ein gwerth newydd fel gwrthrych JSONB. Fodd bynnag, nid oes angen i ni wybod unrhyw ddynodwr ymlaen llaw. Gan edrych ar yr enghraifft EAV, mae angen i ni wybod yr entity_id a'r entity_attribute_id i gyflawni'r diweddariad. Os ydych chi am ddiweddaru priodwedd mewn colofn JSONB yn seiliedig ar enw'r gwrthrych, mae'r cyfan yn cael ei wneud mewn un llinell syml.
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';
Dw i'n meddwl y gallwn ni gytuno bod yr ail yn fyrrach (heb y cyfuniad!) ac felly'n fwy darllenadwy. JSONB sy'n ennill yma! Rydym yn defnyddio'r gweithredwr JSON ->> i adfer y lliw fel gwerth testun o'r gwrthrych JSONB. Mae yna ail ffordd hefyd o gyflawni'r un canlyniad yn y 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 a yw'r gwrthrych JSON yn y golofn priodweddau yn cynnwys y gwrthrych ar ochr dde'r gweithredwr @>. Llai darllenadwy, mwy perfformiol (gweler isod).
Gadewch i ni symleiddio defnyddio JSONB ymhellach fyth pan fydd angen i chi ddewis sawl priodwedd ar unwaith. Dyma lle mae'r dull JSONB yn disgleirio mewn gwirionedd: rydym yn syml yn dewis priodweddau fel colofnau ychwanegol yn ein set ganlyniadau, heb yr angen am ymuniadau:
-- JSONB
SELECT name
, properties ->> 'color'
, properties ->> 'country'
FROM entity_jsonb
WHERE id = 120;
Gyda EAV, bydd angen dau ymuniad arnoch ar gyfer pob priodwedd rydych chi am ei holi. Yn fy marn i, mae'r ymholiadau uchod yn dangos symleiddio sylweddol mewn dylunio cronfeydd data. Gallwch hefyd weld mwy o enghreifftiau o sut i ysgrifennu ymholiadau JSONB yn post.
Nawr mae'n bryd siarad am berfformiad.
Cynhyrchiant
I gymharu'r perfformiad a ddefnyddiais mewn ymholiadau i gyfrifo amser gweithredu. Gweithredwyd pob ymholiad o leiaf dair gwaith, oherwydd bod y cynlluniwr ymholiadau yn cymryd mwy o amser y tro cyntaf. Yn gyntaf, rhedais yr ymholiadau heb unrhyw fynegeion. Roedd hyn yn amlwg yn fantais i JSONB, gan na allai'r uniadau sy'n ofynnol ar gyfer EAV ddefnyddio mynegeion (nid oedd meysydd allwedd dramor wedi'u mynegeio). Ar ôl hynny, creais fynegai ar ddwy golofn allwedd dramor y tabl gwerth EAV, yn ogystal â mynegai ar gyfer colofn JSONB.
Dangosodd diweddariadau data y canlyniadau amser canlynol (mewn ms). Noder bod y raddfa'n logarithmig:

Gwelwn fod JSONB yn sylweddol (>50000x) yn gyflymach nag EAV heb fynegeion, am y rheswm a grybwyllwyd uchod. Pan fyddwn yn mynegeio colofnau allwedd sylfaenol, mae'r gwahaniaeth bron yn diflannu, ond mae JSONB yn dal i fod 1,3x yn gyflymach nag EAV. Sylwch nad oes gan y mynegai ar y golofn JSONB unrhyw effaith yma, gan nad ydym yn defnyddio'r golofn priodwedd yn y meini prawf gwerthuso.
Ar gyfer dewis data yn seiliedig ar werth eiddo, cawn y canlyniadau canlynol (graddfa arferol):

Gallwch weld bod JSONB eto'n gyflymach nag EAV heb fynegeion, ond pan fydd EAV wedi'i fynegeio, mae'n dal yn gyflymach na JSONB. Ond yna gwelais fod yr amseroedd ar gyfer ymholiadau JSONB yr un fath, a arweiniodd fi at y ffaith nad yw mynegeion GIN yn cael eu sbarduno. Yn ôl pob golwg, pan fyddwch chi'n defnyddio mynegai GIN ar golofn gyda phriodweddau poblog, dim ond wrth ddefnyddio'r gweithredwr cynhwysiant @> y mae'n dod i rym. Defnyddiais hwn mewn prawf newydd, ac roedd ganddo effaith enfawr ar yr amser: dim ond 0,153 ms! Mae hynny 15000 gwaith yn gyflymach nag EAV a 25000 gwaith yn gyflymach na'r gweithredwr ->>.
Dw i'n meddwl ei fod yn eithaf cyflym!
Maint tablau cronfa ddata
Gadewch i ni gymharu meintiau tablau ar gyfer y ddau ddull. Yn psql, gallwn arddangos maint yr holl dablau a mynegeion gan ddefnyddio'r gorchymyn dti+

Gyda'r dull EAV, mae meintiau tablau tua 3068 MB, ac mae mynegeion hyd at 3427 MB, am gyfanswm o 6,43 GB. Gan ddefnyddio'r dull JSONB, mae'r tabl yn defnyddio 1817 MB ac yn mynegeio 318 MB, am gyfanswm o 2,08 GB. Dyna draean o'r maint! Synnodd y ffaith hon fi ychydig, gan ein bod yn storio enwau priodweddau ym mhob gwrthrych JSONB.
Ond mae'r niferoedd yn siarad drostynt eu hunain: yn EAV, rydym yn storio dau allwedd dramor cyfanrif fesul gwerth priodoledd, gan arwain at 8 beit o ddata ychwanegol. Ar ben hynny, yn EAV, mae pob gwerth priodwedd yn cael ei storio fel testun, tra bydd JSONB yn defnyddio gwerthoedd rhifiadol a rhesymegol yn fewnol lle bo modd, gan arwain at ôl troed llai.
Canlyniadau
Ar y cyfan, rwy'n credu y gall storio priodweddau endid ar fformat JSONB symleiddio dyluniad a chynnal a chadw eich cronfa ddata yn sylweddol. Os ydych chi'n cynnal llawer o ymholiadau, bydd storio popeth yn yr un tabl â'r endid yn wirioneddol fwy effeithlon. Mae'r ffaith ei fod yn symleiddio rhyngweithiadau data eisoes yn fantais, ond mae'r gronfa ddata sy'n deillio o hyn hefyd dair gwaith yn llai o ran maint.
Hefyd, yn seiliedig ar ganlyniadau'r meincnod, gallwn ddod i'r casgliad bod y gosb perfformiad yn fach iawn. Mewn rhai achosion, mae JSONB hyd yn oed yn perfformio'n gyflymach nag EAV, gan ei wneud hyd yn oed yn well. Fodd bynnag, yn sicr nid yw'r meincnod hwn yn cwmpasu pob agwedd (e.e., endidau â nifer fawr iawn o briodweddau, cynnydd sylweddol yn nifer y priodweddau yn y data presennol, ac ati), felly os oes gennych unrhyw awgrymiadau ar gyfer gwella, mae croeso i chi eu gadael yn y sylwadau!
Ffynhonnell: hab.com
