TL; DR: JSONB استفسار کی کارکردگی کو قربان کیے بغیر ڈیٹا بیس اسکیما کی ترقی کو بہت آسان بنا سکتا ہے۔
تعارف
آئیے ریلیشنل ڈیٹا بیس (ڈیٹا بیس) کی دنیا میں استعمال کے قدیم ترین معاملات میں سے ایک کی ایک کلاسک مثال دیتے ہیں: ہمارے پاس ایک ہستی ہے، اور ہمیں اس ہستی کی کچھ خاص خصوصیات (صفات) کو بچانے کی ضرورت ہے۔ لیکن تمام مثالوں میں خصوصیات کا ایک ہی سیٹ نہیں ہوسکتا ہے، اور مستقبل میں مزید خصوصیات شامل کی جاسکتی ہیں۔
اس مسئلے کو حل کرنے کا سب سے آسان طریقہ یہ ہے کہ ہر پراپرٹی ویلیو کے لیے ڈیٹا بیس ٹیبل میں ایک کالم بنائیں، اور صرف ان کو پُر کریں جو کسی مخصوص ہستی کی مثال کے لیے درکار ہیں۔ زبردست! مسئلہ حل ہو گیا... جب تک کہ آپ کے ٹیبل میں لاکھوں ریکارڈ شامل نہ ہوں اور آپ کو ایک نیا ریکارڈ شامل کرنے کی ضرورت ہو۔
EAV پیٹرن پر غور کریں ()، یہ اکثر ہوتا ہے۔ ایک ٹیبل میں ہستیوں (ریکارڈز) ہوتے ہیں، دوسرے ٹیبل میں پراپرٹی کے نام (اوصاف) ہوتے ہیں، اور تیسرا ٹیبل اداروں کو ان کی صفات سے جوڑتا ہے اور موجودہ ہستی کے لیے ان صفات کی قدر پر مشتمل ہوتا ہے۔ یہ آپ کو مختلف اشیاء کے لیے خصوصیات کے مختلف سیٹ رکھنے کی صلاحیت فراہم کرتا ہے، اور ڈیٹا بیس کی ساخت کو تبدیل کیے بغیر فلائی پر پراپرٹیز بھی شامل کرتا ہے۔
تاہم، میں یہ پوسٹ نہیں لکھوں گا اگر ایوا اپروچ میں کچھ کمی نہ ہوتی۔ لہذا، مثال کے طور پر، ایک یا زیادہ اداروں کو حاصل کرنے کے لیے جن میں ہر ایک میں 1 وصف ہے، استفسار میں 2 جوائنز درکار ہیں: پہلا انتساب جدول کے ساتھ جوائن کرنا ہے، دوسرا ویلیوز ٹیبل کے ساتھ جوائن کرنا ہے۔ اگر کسی ہستی میں 2 صفات ہیں، تو 4 جوائنز کی ضرورت ہے! مزید برآں، تمام اوصاف عام طور پر سٹرنگز کے طور پر محفوظ کیے جاتے ہیں، جس کے نتیجے میں نتیجہ اور WHERE شق دونوں کے لیے ٹائپ کاسٹنگ ہوتی ہے۔ اگر آپ بہت سارے سوالات لکھتے ہیں، تو یہ وسائل کے استعمال کے لحاظ سے کافی فضول ہے۔
ان واضح کوتاہیوں کے باوجود، EAV طویل عرصے سے اس قسم کے مسائل کو حل کرنے کے لیے استعمال ہوتا رہا ہے۔ یہ ناگزیر کوتاہیاں تھیں، اور اس سے بہتر کوئی متبادل نہیں تھا۔
لیکن پھر PostgreSQL میں ایک نئی "ٹیکنالوجی" نمودار ہوئی...
PostgreSQL 9.4 سے شروع کرتے ہوئے، JSONB ڈیٹا کی قسم JSON بائنری ڈیٹا کو ذخیرہ کرنے کے لیے شامل کی گئی تھی۔ اگرچہ اس فارمیٹ میں JSON کو ذخیرہ کرنے میں عام طور پر سادہ متن JSON کے مقابلے میں تھوڑی زیادہ جگہ اور وقت لگتا ہے، لیکن اس پر آپریشن کرنا بہت تیز ہے۔ JSONB انڈیکسنگ کو بھی سپورٹ کرتا ہے، جو سوالات کو اور بھی تیز کرتا ہے۔
JSONB ڈیٹا کی قسم ہمیں ہمارے ہستی ٹیبل میں صرف ایک JSONB کالم شامل کرکے بوجھل EAV پیٹرن کو تبدیل کرنے کی اجازت دیتی ہے، جس سے ڈیٹابیس ڈیزائن کو بہت آسان بنایا جاتا ہے۔ لیکن بہت سے لوگ دلیل دیتے ہیں کہ اس کے ساتھ پیداواری صلاحیت میں کمی ہونی چاہیے... اسی لیے میں نے یہ مضمون لکھا۔
ٹیسٹ ڈیٹا بیس ترتیب دینا
اس موازنہ کے لیے، میں نے $9.5 کی تعمیر پر PostgreSQL 80 کی تازہ تنصیب پر ڈیٹا بیس بنایا۔ 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 آبجیکٹ کے بطور پاس کرنا چاہئے۔ تاہم، ہمیں پہلے سے کسی شناخت کنندہ کو جاننے کی ضرورت نہیں ہے۔ 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 کالم کے لیے۔
ڈیٹا اپ ڈیٹ نے وقت کے لحاظ سے درج ذیل نتائج دکھائے (ایم ایس میں)۔ نوٹ کریں کہ پیمانہ لوگاریتھمک ہے:

ہم دیکھتے ہیں کہ JSONB EAV سے بہت زیادہ تیز ہے اگر آپ اشاریہ جات استعمال نہیں کرتے ہیں، اوپر بیان کردہ وجہ سے۔ جب ہم پرائمری کیز کے ساتھ کالم انڈیکس کرتے ہیں تو فرق تقریباً ختم ہو جاتا ہے، لیکن JSONB اب بھی EAV سے 50000 گنا تیز ہے۔ نوٹ کریں کہ JSONB کالم پر انڈیکس کا یہاں کوئی اثر نہیں ہے کیونکہ ہم تشخیص کے معیار میں پراپرٹی کالم استعمال نہیں کر رہے ہیں۔
پراپرٹی ویلیو کی بنیاد پر ڈیٹا منتخب کرنے کے لیے، ہمیں درج ذیل نتائج ملتے ہیں (عام پیمانہ):

آپ دیکھ سکتے ہیں کہ JSONB پھر سے بغیر اشاریہ کے EAV سے زیادہ تیزی سے کام کرتا ہے، لیکن جب EAV اشاریہ جات کے ساتھ ہوتا ہے، تو یہ JSONB سے زیادہ تیزی سے کام کرتا ہے۔ لیکن پھر میں نے دیکھا کہ JSONB سوالات کے اوقات ایک جیسے تھے، اس نے مجھے اس حقیقت کی طرف اشارہ کیا کہ GIN انڈیکس کام نہیں کرتے۔ بظاہر جب آپ آبادی والی خصوصیات والے کالم پر GIN انڈیکس استعمال کرتے ہیں، تو یہ صرف شامل آپریٹر @> استعمال کرنے پر اثر انداز ہوتا ہے۔ میں نے اسے ایک نئے ٹیسٹ میں استعمال کیا اور اس کا وقت پر بہت زیادہ اثر پڑا: صرف 0,153ms! یہ EAV سے 15000 گنا تیز اور -->> آپریٹر سے 25000 گنا تیز ہے۔
مجھے لگتا ہے کہ یہ کافی تیز تھا!
ڈیٹا بیس ٹیبل کا سائز
آئیے دونوں طریقوں کے لیے جدول کے سائز کا موازنہ کریں۔ psql میں ہم کمانڈ کا استعمال کرتے ہوئے تمام ٹیبلز اور انڈیکس کا سائز دکھا سکتے ہیں۔ dti+

EAV اپروچ کے لیے، ٹیبل کے سائز 3068 MB کے قریب ہیں اور کل 3427 GB کے لیے 6,43 MB تک کے اشاریہ جات ہیں۔ JSONB اپروچ ٹیبل کے لیے 1817 MB اور اشاریہ جات کے لیے 318 MB استعمال کرتا ہے، جو کہ 2,08 GB ہے۔ یہ 3 گنا کم باہر کر دیتا ہے! اس حقیقت نے مجھے تھوڑا سا حیران کیا کیونکہ ہم ہر JSONB آبجیکٹ میں پراپرٹی کے نام محفوظ کرتے ہیں۔
لیکن پھر بھی، نمبر خود ہی بولتے ہیں: EAV میں ہم 2 انٹیجر فارن کیز فی انتساب قدر ذخیرہ کرتے ہیں، جس کے نتیجے میں اضافی ڈیٹا کے 8 بائٹس ہوتے ہیں۔ مزید برآں، EAV تمام پراپرٹی ویلیوز کو ٹیکسٹ کے طور پر اسٹور کرتا ہے، جبکہ JSONB داخلی طور پر عددی اور بولین قدروں کا استعمال کرے گا جہاں ممکن ہو، جس کے نتیجے میں ایک چھوٹا نقشہ ہوگا۔
کے نتائج
مجموعی طور پر، میں سمجھتا ہوں کہ JSONB فارمیٹ میں ہستی کی خصوصیات کو محفوظ کرنا آپ کے ڈیٹا بیس کو ڈیزائن اور برقرار رکھنا بہت آسان بنا سکتا ہے۔ اگر آپ بہت سارے سوالات چلا رہے ہیں، تو ہر چیز کو ایک ہی ٹیبل میں رکھنے سے ہستی اصل میں زیادہ مؤثر طریقے سے کام کرے گی۔ اور حقیقت یہ ہے کہ یہ ڈیٹا کے درمیان تعامل کو آسان بناتا ہے پہلے سے ہی ایک پلس ہے، لیکن نتیجے میں ڈیٹا بیس حجم میں 3 گنا چھوٹا ہے۔
نیز، کئے گئے ٹیسٹوں کی بنیاد پر، ہم یہ نتیجہ اخذ کر سکتے ہیں کہ کارکردگی کا نقصان بہت معمولی ہے۔ کچھ معاملات میں، JSONB EAV سے بھی تیز ہے، اسے اور بھی بہتر بناتا ہے۔ تاہم، یقیناً یہ بینچ مارک تمام پہلوؤں کا احاطہ نہیں کرتا ہے (مثلاً بہت بڑی تعداد میں پراپرٹیز کے حامل ادارے، موجودہ ڈیٹا کی خصوصیات کی تعداد میں نمایاں اضافہ،...)، لہذا اگر آپ کے پاس ان کو بہتر بنانے کے بارے میں کوئی تجاویز ہیں ، تبصرے میں چھوڑنے کے لئے آزاد محسوس کریں!
ماخذ: www.habr.com
