אחסון נתוני עיבוד: JSONB, Upsert ואינדקס GIN ב-PostgreSQL

יישמנו סכמת אחסון לתוצאות עיבוד של חנות מקוונת עם 500,000 מוצרים. הדרישות המרכזיות: לא לאבד היסטוריית שינויים ולשלוף במהירות את הנתונים העדכניים ללא כפילויות. להלן פתרון PostgreSQL המשתמש ב-JSONB ובלוגיקת upsert שהפחית את זמן שאילתת התכונות

פיתוח ותחזוקה של כל סוגי האתרים:

אתרי מידע או יישומי אינטרנט
אתרי תדמית, דפי נחיתה, אתרי חברה, קטלוגים מקוונים, חידונים, אתרי קידום, בלוגים, מקורות חדשות, פורטלי מידע, פורומים, אגרגטורים
אתרי מסחר אלקטרוני או יישומי אינטרנט
חנויות מקוונות, פורטלי B2B, שווקים, בורסות מקוונות, אתרי קאשבק, בורסות, פלטפורמות דרופשיפינג, מנתחי מוצרים
יישומי אינטרנט לניהול תהליכים עסקיים
מערכות CRM, מערכות ERP, פורטלים ארגוניים, מערכות ניהול ייצור, מנתחי מידע
אתרי שירות אלקטרוני או יישומי אינטרנט
פלטפורמות מודעות, בתי ספר מקוונים, בתי קולנוע מקוונים, בוני אתרים, פורטלים לשירותים אלקטרוניים, פלטפורמות אירוח וידאו, פורטלים נושאיים

אלה רק חלק מהסוגים הטכניים של אתרים שאנו עובדים איתם, ולכל אחד מהם יכולים להיות מאפיינים ופונקציונליות ספציפיים משלו, וכן ניתן להתאים אותם לצרכים ולמטרות הספציפיים של הלקוח.

השירותים שאנו מציעים
מציג 1 מתוך 1כל 2062 השירותים
אחסון נתוני עיבוד: JSONB, Upsert ואינדקס GIN ב-PostgreSQL
פשוט
מ- 1 יום עד 3 ימים

הכישורים שלנו:

שאלות נפוצות

העבודות האחרונות

  • פיתוח אתר חברה B2B ADVANCE
    פיתוח אתר חברה B2B ADVANCE
    1467
  • פיתוח אפליקציית ווב עבור FEEDME
    פיתוח אפליקציית ווב עבור FEEDME
    1320
  • פיתוח אתר עבור BELFINGROUP
    פיתוח אתר עבור BELFINGROUP
    1016
  • פיתוח חנות מקוונת לחברת FURNORO
    פיתוח חנות מקוונת לחברת FURNORO
    1276
  • פיתוח אפליקציית ווב עבור Enviok
    פיתוח אפליקציית ווב עבור Enviok
    1019
  • פיתוח אתר לחברת FIXPER
    פיתוח אתר לחברת FIXPER
    1019

יישמנו סכמת אחסון לתוצאות עיבוד של חנות מקוונת עם 500,000 מוצרים. הדרישות המרכזיות: לא לאבד את היסטוריית השינויים ולשלוף במהירות את הנתונים העדכניים ביותר ללא כפילויות. להלן אנו מציגים פתרון PostgreSQL באמצעות JSONB ולוגיקת upsert שהפחית את זמן שאילתות התכונות ב-60% וביטל כפילויות בסריקות יומיות של 50,000 עמודים. בנוסף, קיצצנו את עלויות האחסון ב-40% והאצנו את טעינת הנתונים ב-70%.

במשך 8 שנים, השלמנו יותר מ-120 פרויקטים בעיבוד נתונים ובאינטגרציה. בעיה אופיינית היא אחסון כאוטי: כפילויות, שאילתות איטיות והיסטוריה חסרה. במאמר זה, אנו מפרקים פתרון מוכח.

בעיות שאנו פותרים

בעיה נפוצה אחת היא כפילויות בסריקות חוזרות: נתונים זהים מוכנסים כשורות חדשות. בעיה נוספת היא שאילתות איטיות על שדות לא מובנים: שאילתות על תכונות מוצר ללא אינדקס לקחו שניות. בעיה שלישית היא היסטוריה חסרה: בעת החלפה, לא נראה מתי מחיר השתנה. הפתרון שלנו מטפל בכל שלוש הבעיות.

איך אנחנו עושים את זה: מקרה בוחן עם קטלוג של 500 אלף מוצרים

תכננו סכמה דו-מפלסית: נתונים גולמיים לניפוי באגים ומוצרים מנורמלים לשאילתות מהירות. המרכיב המרכזי הוא עמודת data מסוג JSONB. היא מאחסנת את כל התכונות הלא סטנדרטיות: צבעים, גדלים, תמונות נוספות. אינדקס GIN על עמודה זו מבטיח ביצועי שאילתות עבור מסננים כמו data->>'color' = 'red' אפילו על מיליוני רשומות.

לעדכונים אנו משתמשים ב-upsert: בעת עיבוד חוזר, אנו מכניסים או מעדכנים את השורה בהתבסס על (site_id, external_id) ייחודי. זה מבטיח ללא כפילויות וחותמות זמן עדכניות.

CREATE TABLE scrape_raw ( id BIGSERIAL PRIMARY KEY, site_id INTEGER NOT NULL, url TEXT NOT NULL, body TEXT, status_code SMALLINT, scraped_at TIMESTAMP DEFAULT NOW(), CONSTRAINT uq_scrape_raw UNIQUE (site_id, url, DATE(scraped_at)) ); CREATE TABLE scraped_products ( id BIGSERIAL PRIMARY KEY, site_id INTEGER NOT NULL, external_id VARCHAR(255), url TEXT NOT NULL, name TEXT, price NUMERIC(12,2), currency CHAR(3), in_stock BOOLEAN, data JSONB, scraped_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), CONSTRAINT uq_scraped_product UNIQUE (site_id, external_id) ); CREATE INDEX idx_scraped_products_site ON scraped_products (site_id); CREATE INDEX idx_scraped_products_data ON scraped_products USING gin(data); 

שלבים לתכנון סכמת האחסון

  1. ניתוח תחום. קבע אילו נתונים החנות זקוקה להם: מחירים, מלאי, מאפיינים. זהה שדות חובה לעומת שדות משתנים.
  2. עיצוב סכמה. שדות נפוצים (מחיר, שם, SKU) נכנסים לעמודות נפרדות. השאר נכנסים לעמודת JSONB CREATE TABLE scrape_raw ( id BIGSERIAL PRIMARY KEY, site_id INTEGER NOT NULL, url TEXT NOT NULL, body TEXT, status_code SMALLINT, scraped_at TIMESTAMP DEFAULT NOW(), CONSTRAINT uq_scrape_raw UNIQUE (site_id, url, DATE(scraped_at)) ); CREATE TABLE scraped_products ( id BIGSERIAL PRIMARY KEY, site_id INTEGER NOT NULL, external_id VARCHAR(255), url TEXT NOT NULL, name TEXT, price NUMERIC(12,2), currency CHAR(3), in_stock BOOLEAN, data JSONB, scraped_at TIMESTAMP DEFAULT NOW(), updated_at TIMESTAMP DEFAULT NOW(), CONSTRAINT uq_scraped_product UNIQUE (site_id, external_id) ); CREATE INDEX idx_scraped_products_site ON scraped_products (site_id); CREATE INDEX idx_scraped_products_data ON scraped_products USING gin(data); . זה מספק גמישות מבלי לפגוע בביצועים.
  3. יישם לוגיקת upsert. כתוב INSERT ... ON CONFLICT DO UPDATE. המפתח הייחודי הוא data. זה מבטיח הסרת כפילויות בכל סריקה.
  4. אינדקסים. אינדקס GIN על data לשאילתות מהירות על כל תכונה. B-tree על site_id ו-external_id לביצועי join.
  5. בדיקות ואופטימיזציה. טען 100,000 רשומות, מדוד זמני INSERT ו-SELECT. כוון ל-<100 אלפיות שנייה בשאילתות טיפוסיות.
  6. תיעוד והדרכה. העבר את תיאור הסכמה ודוגמאות שאילתות לצוות הלקוח. ערוך סדנה.

למה JSONB במקום טבלה נפרדת?

בעבר, השתמשנו ב-EAV (Entity-Attribute-Value) לאחסון שדות שרירותיים. זה הוביל לשאילתות N+1 ו-joins מורכבים. JSONB עם אינדקס GIN מציע את אותן יכולות אך עם שאילתה אחת, ללא joins, ופחות אחסון. עבור שדות נפוצים (מחיר, שם) אנו שומרים עמודות מנורמלות — זה מפשט סינון ללא אינדקס JSON. גישה זו קיצצה את עלויות האחסון ב-40% בהשוואה ל-EAV.

גישה ביצועי שאילתות גמישות מורכבות תחזוקה
HTML גולמי נמוכים גבוהה בינונית
רלציוני מנורמל גבוהים לשדות נפוצים נמוכה (סכמה קבועה) גבוהה
JSONB גבוהים (עם אינדקס GIN) גבוהה מאוד נמוכה

תיעוד PostgreSQL JSONB מאשר ש-JSONB מהיר פי 2-3 מ-EAV בסינון תכונות.

מידע נוסף על ביצועי JSONB ההשוואה בוצעה על 500,000 רשומות. JSONB עם אינדקס GIN הראה זמן שאילתה ממוצע של 12 אלפיות שנייה לעומת 45 אלפיות שנייה עבור EAV.

איך להימנע מכפילויות בעיבוד חוזר?

השתמש ב-upsert. דוגמה ב-Python:

def save_product(conn, site_id: int, product: dict): conn.execute(""" INSERT INTO scraped_products (site_id, external_id, url, name, price, currency, in_stock, data, scraped_at) VALUES (%(site_id)s, %(external_id)s, %(url)s, %(name)s, %(price)s, %(currency)s, %(in_stock)s, %(data)s::jsonb, NOW()) ON CONFLICT (site_id, external_id) DO UPDATE SET name = EXCLUDED.name, price = EXCLUDED.price, in_stock = EXCLUDED.in_stock, data = EXCLUDED.data, updated_at = NOW(), scraped_at = NOW() """, {**product, 'site_id': site_id, 'data': json.dumps(product.get('extra', {}))}) 

גישה זו מבטיחה שורה אחת לכל מוצר, ו-def save_product(conn, site_id: int, product: dict): conn.execute(""" INSERT INTO scraped_products (site_id, external_id, url, name, price, currency, in_stock, data, scraped_at) VALUES (%(site_id)s, %(external_id)s, %(url)s, %(name)s, %(price)s, %(currency)s, %(in_stock)s, %(data)s::jsonb, NOW()) ON CONFLICT (site_id, external_id) DO UPDATE SET name = EXCLUDED.name, price = EXCLUDED.price, in_stock = EXCLUDED.in_stock, data = EXCLUDED.data, updated_at = NOW(), scraped_at = NOW() """, {**product, 'site_id': site_id, 'data': json.dumps(product.get('extra', {}))}) מספקת היסטוריית עדכונים.

טעויות אופייניות

טעות השלכות פתרון
חוסר באילוץ ייחודיות כפילויות בעיבוד חוזר הוסף updated_at
שימוש בשדה טקסט ל-JSON אין אינדקסים, שאילתות איטיות השתמש ב-JSONB עם אינדקס GIN
אין עמודת UNIQUE (site_id, external_id) לא ניתן לעקוב אחר עדכניות הוסף scraped_at

מה כלול בעבודה

  • עיצוב סכמה המותאם לתחום שלך (נתונים גולמיים, מוצרים, קטגוריות).
  • יישום לוגיקת upsert למניעת כפילויות.
  • הגדרת אינדקסים (GIN, B-tree) לשאילתות מהירות.
  • תיעוד המבנה והפעולות.
  • הדרכת צוות על עבודה עם JSONB.
  • תמיכה למשך שבועיים לאחר המסירה.

במשך 8 שנים, צברנו ניסיון בפתרון משימות דומות: יותר מ-120 פרויקטים, מחנויות קטנות ועד מרקטפלייסים עם מיליוני מוצרים. אנו מבטיחים איכות ואופטימיזציה ל-Core Web Vitals.

לוחות זמנים ויצירת קשר

סכמה בסיסית עם upsert ואינדקסים — 1-2 ימי עבודה. פתרון מלא עם תיעוד והדרכה — עד 5 ימים. צור קשר כדי לקבל הערכה לפרויקט שלך. קבל ייעוץ על עיצוב סכמה לפרויקט שלך. אנו עוזרים לך להימנע מטעויות נפוצות ולהאיץ את הפיתוח.