JSONB ב-Postgres: מתי טבלה גמישה עדיפה על סכמה קשיחה, ולהפך
מאת צוות מדיה דיל · 03.09.2026 · טכנולוגיה · 6 דק׳
ההבדל בין JSON ל-JSONB, אינדוקס GIN ואופרטורי @>/?/#>>, Generated Columns כפשרה, ולמה JSONB הוא לא תירוץ להימנע ממידול נתונים.
"בואו נוסיף עמודה" הופך למשימה כבדה כשהטבלה מכילה מאות מיליוני שורות ודורשת Migration חוסם. JSONB ב-Postgres מציע דרך לגמישות סכמה בלי לוותר על מסד נתונים יחסי אמיתי — אבל הוא פתרון לבעיה ספציפית, לא תחליף כללי למידול נתונים נכון, וטעות נפוצה היא להשתמש בו בדיוק כשהמקרה קורא לטבלה רגילה.
JSON מול JSONB: לא רק שם אחר
עמודת JSON שומרת את הטקסט כמו שהוא, כולל רווחים וסדר מפתחות, ומפרשת אותו מחדש בכל שאילתה. JSONB שומר ייצוג בינארי מפורק מראש — כתיבה איטית מעט יותר, אבל קריאה ואינדוקס מהירים משמעותית, כי Postgres לא צריך לפרסר טקסט בכל גישה. כמעט תמיד JSONB הוא הבחירה הנכונה בפרודקשן; JSON רגיל שימושי בעיקר כשצריך לשמר סדר מפתחות מדויק, למשל בלוג ביקורת שמצפה בדיוק את מה שהתקבל מגורם חיצוני.
מתי JSONB באמת עדיף על סכמה קשיחה
כשהשדות הדינמיים הם באמת לא ידועים מראש ומשתנים בין רשומות — custom fields שכל לקוח מגדיר לעצמו, payload של Webhook חיצוני, או הגדרות תצורה שמשתנות בתדירות גבוהה — JSONB חוסך Migration על כל שינוי סכמה. זה שימושי גם ב-Multi-Tenant שבו כל דייר צריך שדות שונים; ראו ארכיטקטורת Multi-Tenant לדיון מלא בבידוד דיירים.
ומתי טבלה רגילה עדיפה — כמעט תמיד
אם השדה קיים בכל שורה, יש לו טיפוס ברור, והוא משתתף ב-JOIN או ב-Foreign Key — הוא שייך לעמודה רגילה. Postgres אוכף טיפוסים, Not Null ו-Foreign Keys ברמת המסד רק על עמודות רגילות; בתוך JSONB אין אכיפה כזו בכלל, וכל טעות מבנית מתגלה רק בזמן ריצה בקוד האפליקציה, לא בזמן כתיבה למסד. הכלל המעשי: אם אפשר לצייר תרשים ER ברור לשדה, הוא כנראה שייך לעמודה רגילה, לא לתוך מסמך.
אינדוקס GIN: מה שהופך שאילתות JSONB למהירות
אינדקס GIN (Generalized Inverted Index) על עמודת JSONB מאפשר לשאילתות עם האופרטור @> (containment) לרוץ ביעילות דומה לאינדקס B-Tree על עמודה רגילה. בלי GIN, כל שאילתה שמחפשת בתוך ה-JSON היא Seq Scan מלא על הטבלה — כדאי להשוות למנגנון B-Tree שמתואר באינדוקס ב-Postgres כדי להבין למה בלי אינדקס נכון הביצועים קורסים מהר עם גדילת הטבלה.
אופרטורים מרכזיים: @>, ?, #>>
@> בודק הכלה של מבנה JSON שלם, ? בודק קיום מפתח בודד, ו-#>> שולף ערך מנתיב מקונן כטקסט. השילוב הנכון בין האופרטורים לאינדקס הוא קריטי: אינדקס GIN רגיל תומך היטב ב-@> אבל פחות יעיל לחיפוש טקסט חלקי בתוך ערך — לכך נדרש אינדקס ייעודי נוסף (jsonb_path_ops או Trigram) לפי דפוס השאילתה בפועל.
Generated Columns: הפשרה הביניים
כשיש שדה בודד בתוך JSONB שנשאל בתדירות גבוהה במיוחד, אפשר להוציא אותו לעמודה Generated רגילה (GENERATED ALWAYS AS) שמתעדכנת אוטומטית מהערך בתוך ה-JSON ומקבלת אינדקס B-Tree רגיל משלה. זו טכניקה מעשית שנותנת ביצועי שאילתה של עמודה רגילה בלי לוותר על גמישות שאר השדות, ומאפשרת גם להוסיף עליה Constraint רגיל כמו Not Null או בדיקת טווח, שלא ניתן לאכוף ישירות בתוך ה-JSON.
המלכודת הנפוצה: JSONB כתחליף למידול
הסכנה האמיתית היא לא ביצועים אלא משמעת: כשקל מדי להוסיף שדה חדש ל-JSONB, הפיתוי הוא להימנע ממידול נתונים כראוי ולזרוק הכל פנימה. התוצאה בעוד שנה היא טבלה עם JSONB ענק חסר מבנה ברור, שאף אחד לא זוכר איזה שדה קיים באיזו רשומה, ושכל שאילתה חדשה דורשת ניחוש. JSONB הוא כלי לגמישות מכוונת, לא תירוץ לדחות החלטות מידול.
מתלבטים איך למדל נתונים דינמיים בלי לפגוע בביצועים או בעקביות? נשמח לעזור לכם לתכנן סכמה נכונה בוואטסאפ.
תגיות: JSONB · Postgres · Database Design · GIN Index