PostgreSQL இல் EAV ஐ JSONB உடன் மாற்றுகிறது

TL; DR: JSONB வினவல் செயல்திறனைத் தியாகம் செய்யாமல் தரவுத்தளத் திட்ட மேம்பாட்டை பெரிதும் எளிதாக்கும்.

அறிமுகம்

தொடர்புடைய தரவுத்தளத்தின் (தரவுத்தளத்தின்) உலகின் மிகப் பழமையான பயன்பாட்டு நிகழ்வுகளில் ஒன்றின் சிறந்த உதாரணத்தை வழங்குவோம்: எங்களிடம் ஒரு நிறுவனம் உள்ளது, மேலும் இந்த நிறுவனத்தின் சில பண்புகளை (பண்புகளை) சேமிக்க வேண்டும். ஆனால் எல்லா நிகழ்வுகளும் ஒரே மாதிரியான பண்புகளைக் கொண்டிருக்க முடியாது, மேலும் எதிர்காலத்தில் மேலும் பண்புகள் சேர்க்கப்படலாம்.

இந்தச் சிக்கலைத் தீர்ப்பதற்கான எளிதான வழி, ஒவ்வொரு சொத்து மதிப்புக்கும் தரவுத்தள அட்டவணையில் ஒரு நெடுவரிசையை உருவாக்குவது மற்றும் ஒரு குறிப்பிட்ட நிறுவன நிகழ்விற்குத் தேவையானவற்றை நிரப்புவது. நன்று! சிக்கல் தீர்க்கப்பட்டது... உங்கள் டேபிளில் மில்லியன் கணக்கான பதிவுகள் இருக்கும் வரை, நீங்கள் ஒரு புதிய பதிவைச் சேர்க்க வேண்டும்.

EAV வடிவத்தைக் கவனியுங்கள் (பொருள்-பண்பு-மதிப்பு), இது அடிக்கடி நிகழ்கிறது. ஒரு அட்டவணையில் உட்பொருள்கள் (பதிவுகள்) உள்ளன, மற்றொரு அட்டவணையில் சொத்துப் பெயர்கள் (பண்புகள்) உள்ளன, மேலும் மூன்றாவது அட்டவணை நிறுவனங்களை அவற்றின் பண்புகளுடன் தொடர்புபடுத்துகிறது மற்றும் தற்போதைய நிறுவனத்திற்கான பண்புகளின் மதிப்பைக் கொண்டுள்ளது. இது வெவ்வேறு பொருட்களுக்கான வெவ்வேறு பண்புகளை வைத்திருக்கும் திறனை உங்களுக்கு வழங்குகிறது, மேலும் தரவுத்தள கட்டமைப்பை மாற்றாமல் பறக்கும் போது பண்புகளை சேர்க்கிறது.

இருப்பினும், ஈ.வி.ஏ அணுகுமுறையில் சில குறைபாடுகள் இல்லாவிட்டால் நான் இந்த இடுகையை எழுத மாட்டேன். எனவே, எடுத்துக்காட்டாக, ஒவ்வொன்றும் 1 பண்புக்கூறுகளைக் கொண்ட ஒன்று அல்லது அதற்கு மேற்பட்ட நிறுவனங்களைப் பெற, வினவலில் 2 இணைப்புகள் தேவை: முதலாவது பண்புக்கூறு அட்டவணையுடன் இணைவது, இரண்டாவது மதிப்புகள் அட்டவணையுடன் இணைவது. ஒரு பொருளுக்கு 2 பண்புக்கூறுகள் இருந்தால், 4 இணைப்புகள் தேவை! கூடுதலாக, அனைத்து பண்புக்கூறுகளும் பொதுவாக சரங்களாக சேமிக்கப்படுகின்றன, இதன் விளைவாக முடிவு மற்றும் WHERE பிரிவு இரண்டிற்கும் வகை வார்ப்பு ஏற்படுகிறது. நீங்கள் நிறைய வினவல்களை எழுதினால், வளங்களைப் பயன்படுத்துவதில் இது மிகவும் வீணானது.

இந்த வெளிப்படையான குறைபாடுகள் இருந்தபோதிலும், இந்த வகையான சிக்கல்களை தீர்க்க EAV நீண்ட காலமாக பயன்படுத்தப்படுகிறது. இவை தவிர்க்க முடியாத குறைபாடுகள், மேலும் சிறந்த மாற்று எதுவும் இல்லை.
ஆனால் பின்னர் PostgreSQL இல் ஒரு புதிய "தொழில்நுட்பம்" தோன்றியது...

PostgreSQL 9.4 இல் தொடங்கி, JSON பைனரி தரவைச் சேமிக்க JSONB தரவு வகை சேர்க்கப்பட்டது. இந்த வடிவமைப்பில் JSON ஐ சேமிப்பது பொதுவாக JSON என்ற எளிய உரையை விட சற்று அதிக இடத்தையும் நேரத்தையும் எடுக்கும் என்றாலும், அதன் செயல்பாடுகள் மிக வேகமாக இருக்கும். JSONB அட்டவணைப்படுத்தலையும் ஆதரிக்கிறது, இது வினவல்களை இன்னும் வேகமாக்குகிறது.

JSONB தரவு வகையானது, எங்கள் நிறுவன அட்டவணையில் ஒரு JSONB நெடுவரிசையைச் சேர்ப்பதன் மூலம் சிக்கலான EAV வடிவத்தை மாற்ற அனுமதிக்கிறது, இது தரவுத்தள வடிவமைப்பை பெரிதும் எளிதாக்குகிறது. ஆனால், இதனுடன் உற்பத்தித் திறன் குறையும் என்று பலர் வாதிடுகிறார்கள்... அதனால்தான் இந்தக் கட்டுரையை எழுதினேன்.

சோதனை தரவுத்தளத்தை அமைத்தல்

இந்த ஒப்பீட்டிற்காக, நான் $9.5 உருவாக்கத்தில் PostgreSQL 80 இன் புதிய நிறுவலில் தரவுத்தளத்தை உருவாக்கினேன். DigitalOcean உபுண்டு 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 வெளிநாட்டு விசை நெடுவரிசைகளில் ஒரு குறியீட்டை உருவாக்கினேன், அத்துடன் ஒரு குறியீட்டையும் உருவாக்கினேன். ஜின் JSONB நெடுவரிசைக்கு.

தரவு புதுப்பிப்பு நேரத்தின் அடிப்படையில் பின்வரும் முடிவுகளைக் காட்டியது (மிஎஸ்களில்). அளவுகோல் மடக்கை என்பதை நினைவில் கொள்ளவும்:

PostgreSQL இல் EAV ஐ JSONB உடன் மாற்றுகிறது

மேலே கூறப்பட்ட காரணத்திற்காக, நீங்கள் குறியீடுகளைப் பயன்படுத்தாவிட்டால், EAV ஐ விட JSONB மிகவும் (> 50000-x) வேகமானது என்பதை நாங்கள் காண்கிறோம். முதன்மை விசைகளுடன் நெடுவரிசைகளை அட்டவணைப்படுத்தும்போது, ​​வேறுபாடு கிட்டத்தட்ட மறைந்துவிடும், ஆனால் JSONB இன்னும் EAV ஐ விட 1,3 மடங்கு வேகமாக உள்ளது. மதிப்பாய்வு அளவுகோலில் உள்ள சொத்து நெடுவரிசையை நாங்கள் பயன்படுத்தாததால், JSONB நெடுவரிசையில் உள்ள குறியீடானது இங்கு எந்த விளைவையும் ஏற்படுத்தாது என்பதை நினைவில் கொள்ளவும்.

சொத்து மதிப்பின் அடிப்படையில் தரவைத் தேர்ந்தெடுப்பதற்கு, பின்வரும் முடிவுகளைப் பெறுவோம் (சாதாரண அளவு):

PostgreSQL இல் EAV ஐ JSONB உடன் மாற்றுகிறது

குறியீடுகள் இல்லாமல் EAV ஐ விட JSONB மீண்டும் வேகமாகச் செயல்படுவதை நீங்கள் கவனிக்கலாம், ஆனால் EAV இன்டெக்ஸ்களுடன் இருக்கும்போது, ​​அது JSONB ஐ விட வேகமாகச் செயல்படும். ஆனால் JSONB வினவல்களுக்கான நேரங்கள் ஒரே மாதிரியாக இருப்பதை நான் பார்த்தேன், இது ஜிஐஎன் இன்டெக்ஸ்கள் வேலை செய்யாது என்று என்னைத் தூண்டியது. மக்கள்தொகை கொண்ட பண்புகளைக் கொண்ட நெடுவரிசையில் நீங்கள் ஜிஐஎன் குறியீட்டைப் பயன்படுத்தும் போது, ​​@> உள்ளிட்ட ஆபரேட்டரைப் பயன்படுத்தும் போது மட்டுமே அது செயல்படும். நான் இதை ஒரு புதிய சோதனையில் பயன்படுத்தினேன், அது நேரத்தில் பெரும் தாக்கத்தை ஏற்படுத்தியது: 0,153ms மட்டுமே! இது EAV ஐ விட 15000 மடங்கு வேகமானது மற்றும் ->> ஆபரேட்டரை விட 25000 மடங்கு வேகமானது.

அது போதுமான வேகமாக இருந்தது என்று நினைக்கிறேன்!

தரவுத்தள அட்டவணை அளவு

இரண்டு அணுகுமுறைகளுக்கும் அட்டவணை அளவுகளை ஒப்பிடுவோம். psql இல் கட்டளையைப் பயன்படுத்தி அனைத்து அட்டவணைகள் மற்றும் குறியீடுகளின் அளவைக் காட்டலாம் டிடிஐ+

PostgreSQL இல் EAV ஐ JSONB உடன் மாற்றுகிறது

EAV அணுகுமுறைக்கு, அட்டவணை அளவுகள் சுமார் 3068 MB மற்றும் குறியீடுகள் 3427 MB வரை மொத்தம் 6,43 GB. JSONB அணுகுமுறை அட்டவணைக்கு 1817 MB மற்றும் குறியீடுகளுக்கு 318 MB ஐப் பயன்படுத்துகிறது, அதாவது 2,08 GB. இது 3 மடங்கு குறைவாக மாறிவிடும்! ஒவ்வொரு JSONB பொருளிலும் சொத்துப் பெயர்களைச் சேமித்து வைப்பதால் இந்த உண்மை எனக்குக் கொஞ்சம் ஆச்சரியமாக இருந்தது.

இருப்பினும், எண்கள் தங்களைத் தாங்களே பேசுகின்றன: EAV இல் ஒரு பண்புக்கூறு மதிப்பிற்கு 2 முழு எண் வெளிநாட்டு விசைகளை சேமிக்கிறோம், இதன் விளைவாக 8 பைட்டுகள் கூடுதல் தரவு கிடைக்கும். கூடுதலாக, EAV ஆனது அனைத்து சொத்து மதிப்புகளையும் உரையாக சேமிக்கிறது, அதே நேரத்தில் JSONB எண் மற்றும் பூலியன் மதிப்புகளை முடிந்தவரை உள்நாட்டில் பயன்படுத்தும், இதன் விளைவாக சிறிய தடம் கிடைக்கும்.

முடிவுகளை

ஒட்டுமொத்தமாக, JSONB வடிவமைப்பில் நிறுவன பண்புகளைச் சேமிப்பது உங்கள் தரவுத்தளத்தை வடிவமைத்து பராமரிப்பதை மிகவும் எளிதாக்கும் என்று நினைக்கிறேன். நீங்கள் நிறைய வினவல்களை இயக்குகிறீர்கள் என்றால், எல்லாவற்றையும் ஒரே அட்டவணையில் வைத்திருப்பது உண்மையில் மிகவும் திறமையாக வேலை செய்யும். இது தரவுகளுக்கு இடையிலான தொடர்புகளை எளிதாக்குகிறது என்பது ஏற்கனவே ஒரு பிளஸ் ஆகும், ஆனால் இதன் விளைவாக தரவுத்தளம் 3 மடங்கு சிறியதாக உள்ளது.

மேலும், நிகழ்த்தப்பட்ட சோதனைகளின் அடிப்படையில், செயல்திறன் இழப்புகள் மிகவும் அற்பமானவை என்று நாம் முடிவு செய்யலாம். சில சமயங்களில், EAV ஐ விட JSONB இன்னும் வேகமானது, இது இன்னும் சிறப்பாக உள்ளது. இருப்பினும், இந்த அளவுகோல் நிச்சயமாக அனைத்து அம்சங்களையும் உள்ளடக்காது (எ.கா. அதிக எண்ணிக்கையிலான பண்புகளைக் கொண்ட நிறுவனங்கள், ஏற்கனவே உள்ள தரவின் பண்புகளின் எண்ணிக்கையில் குறிப்பிடத்தக்க அதிகரிப்பு,...), எனவே அவற்றை எவ்வாறு மேம்படுத்துவது என்பது குறித்து உங்களிடம் ஏதேனும் பரிந்துரைகள் இருந்தால் , தயவு செய்து கருத்துகளில் விட்டுவிடுங்கள்!

ஆதாரம்: www.habr.com

கருத்தைச் சேர்