Tune PostgreSQL for pgvector

הושלם

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

הערה

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

דרישות חישוב וזיכרון של Pgvector

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

כשאתה מבצע שאילתת דמיון וקטורי, pgvector חייב לחשב את המרחק בין וקטור השאילתה לוקטור המועמדים. עבור הטמעה ב-1536 ממד (נפוץ במודלים של OpenAI), כל חישוב מרחק כולל 1,536 פעולות נקודה צפה. חיפוש של מיליון וקטורים ללא אינדקס דורש מעל 1.5 מיליארד פעולות נקודה צפה לכל שאילתה. שלוש פונקציות המרחק נושאות עלויות חישוביות שונות שמשפיעות על הבחירה שלך בהתאם למאפייני הנתונים ולדרישות הביצועים שלך.

  • מרחק L2 (אוקלידי): משתמש באופרטור <-> ומחשב את השורש הריבועי של סכום ההפרשים בריבוע. זו האפשרות היקרה ביותר מבחינה חישובית.
  • מרחק קוסינוס: משתמש באופרטור <=> ומודד את הזווית בין וקטורים. הוא מנרמל וקטורים פנימית, מוסיף חישוב אך מספק דמיון בלתי משתנה בקנה מידה.
  • המוצר הפנימי: משתמש באופרטור <#> ומחשב את מכפלת הנקודות. זו הפעולה המהירה ביותר אך דורשת וקטורים מנורמליים מראש להשוואות דמיון משמעותיות.

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

עמודות וקטוריות צורכות אחסון משמעותי בהשוואה לסוגי נתונים מסורתיים. וקטור יחיד בעל 1536 ממד המאוחסן כ float4 -(דיוק יחיד) דורש 6,144 בתים, בתוספת עומס. טבלה עם מיליון הטמעות-מוצר דורשת בערך 6GB רק עבור עמודת הווקטור. כאשר PostgreSQL מעבד שאילתות וקטוריות, הוא טוען נתוני וקטור לזיכרון. הקשר בין הזיכרון הזמין לגודל הנתונים הווקטוריים משפיע ישירות האם שאילתות יכולות לפעול ביעילות בזיכרון או שיש לקרוא אותן שוב ושוב מהדיסק.

הטבעות במימד גבוה יותר מספקות רזולוציה סמנטית גבוהה יותר אך מגדילות הן את עלויות האחסון והן את עלויות החישוב באופן ריבועי. וקטור 3072 ממד (בשימוש במודלים חדשים של הטמעה) דורש פי ארבעה מעבודת חישוב מרחק ואחסון כפול מווקטור 1536 ממד. שקלו את דרישות הדיוק שלכם בעת בחירת מידות הטמעה. עבור יישומי המלצה וחיפוש רבים, 768 או 1,024 ממדים מספקים איכות מספקת עם צריכת משאבים נמוכה משמעותית.

תצורת זיכרון לעומסי עבודה וקטוריים

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

הפרמטר shared_buffers שולט במטמון הזיכרון המשותף של PostgreSQL, שבו נמצאים דפי הנתונים הנגישים לעיתים קרובות. לעומסי עבודה וקטוריים, המטמון הזה צריך להיות גדול מספיק כדי להכיל את אינדקסי הווקטורים והנתונים החמים. יחס פגיעות במטמון מתחת ל-99% עבור עומסי עבודה כבדים וקטור מצביע על כך שזה shared_buffers עשוי להיות קטן מדי. ב-Azure Database for PostgreSQL, הפרמטר הזה מכוון אוטומטית לפי שכבת החישוב שלך, אבל אפשר להתאים אותו בטווח המותר לדרגה שלך. לעומסי עבודה ייעודיים בחיפוש וקטורי, תכוון לגדול shared_buffers מספיק כדי להחזיק את אינדקסי הווקטורים שלך וגם מרווח לנתונים אחרים שמאוחסנים. נקודת התחלה היא 25% זיכרון זמין, עם עלייה המבוססת על ניטור. השאילתות הבאות עוזרות לך לבדוק את ההגדרות הנוכחיות שלך ואת ביצועי המטמון.

-- Check current setting
SHOW shared_buffers;

-- View buffer cache hit ratio
SELECT
    sum(heap_blks_hit) / (sum(heap_blks_hit) + sum(heap_blks_read)) AS cache_hit_ratio
FROM pg_statio_user_tables;

הפרמטר work_mem שולט בזיכרון הזמין לפעולות שאילתה בודדות כמו מיון והצטרפות גיבוב. שאילתות דמיון וקטורי, במיוחד אלו שמשלבות חיפוש וקטורי עם סינון וסידור, נהנות משאילתות work_memמספקת . ברירת המחדל work_mem (בדרך כלל 4MB) לרוב קטנה מדי עבור פעולות וקטוריות שצריכות למיין תוצאות לפי דמיון. ניתן להגדיל ערך זה עבור סשנים או שאילתות שמבצעים חיפושי וקטור עם קבוצות תוצאות גדולות באמצעות SET work_mem = '256MB';. היזהר עם הגדלות גלובליות כי work_mem ההגדרה חלה לכל פעולה לכל חיבור, ולכן שרת שמטפל ב-100 חיבורים מקבילים עם שאילתות מורכבות עלול לצרוך 100 × work_mem × פעולות לכל שאילתה. לגבי עומסי עבודה וקטוריים, שקול להגדיר work_mem את זה ברמת הסשן עבור שאילתות ספציפיות במקום גלובלית.

הפרמטר effective_cache_size אומר למתכנן השאילתות כמה זיכרון זמין למטמון, כולל מטמון הקבצים של PostgreSQL shared_buffers ושל מערכת ההפעלה. הגדרה זו לא מקצה זיכרון אך משפיעה האם המתכנן יבחר בסריקות אינדקס על פני סריקות עוקבות. הוגדר effective_cache_size לכ-75% של זיכרון מערכת כולל בשרתים ייעודיים של מסדי נתונים. ערכים גבוהים יותר מעודדים את המתכנן להשתמש באינדקסים, דבר שבדרך כלל מועיל לחיפוש וקטורי. ב-Azure Database for PostgreSQL, זה מוגדר אוטומטית לפי הרמה שלך.

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

random_page_cost הפרמטר מעריך את עלות קריאת דף דיסק אקראי ביחס לעמוד רציף. הערך ברירת המחדל של 4.0 משקף מאפייני דיסק מסתובב שבהם הגישה האקראית איטית משמעותית מגישה רציפה. Azure Database עבור PostgreSQL משתמש באחסון SSD שבו גישה אקראית ורציפה פועלת בביצועים דומים. הורדה random_page_cost ל-1.1-1.5 מעודדת את המתכנן להשתמש בסריקות אינדקס בקלות רבה יותר, מה שמועיל לחיפושים וקטוריים שמגיעים לדפי נתונים מפוזרים. אתה יכול לכוון את ההגדרה הזו עם SET random_page_cost = 1.1;.

effective_io_concurrency הפרמטר מראה ל-PostgreSQL כמה פעולות קלט/פלט בדיסק מקביל מערכת האחסון יכולה לטפל בהן. ערכים גבוהים יותר מאפשרים לסריקות ערימת ביטמאפ לשלוף מראש יותר דפים במקביל. אחסון SSD מטפל היטב בקלט/פלט בו-זמנית, ולכן מוגדר effective_io_concurrency ל-200 עבור Azure Database מבוסס SSD עבור מופעי PostgreSQL. זה משפר את הביצועים עבור שאילתות שמשלבות דמיון וקטורי עם סינון מטא-דאטה.

הפרמטרים parallel_tuple_cost של ו parallel_setup_cost שולטים כאשר PostgreSQL משתמש בביצוע שאילתות מקביל. פעולות וקטוריות יכולות להרוויח ממקביליות, במיוחד בסריקות רציפות בטבלאות גדולות. ערכים נמוכים יותר עבור parallel_tuple_cost (ברירת מחדל 0.1) ו parallel_setup_cost -(ברירת מחדל 1000) מעודדים ביצוע מקביל. בעומסי עבודה וקטוריים עם טבלאות גדולות, הפעלת מקביליות יכולה לקצר משמעותית את זמן השאילתה כאשר אינדקסים אינם בשימוש. אתה יכול לבדוק את ההגדרות המקביליות הנוכחיות שלך באמצעות SHOW parallel_tuple_cost;, SHOW parallel_setup_cost;, ו- SHOW max_parallel_workers_per_gather;.

הגדרת פרמטרים ספציפיים ל-pgvector

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

כאשר משתמשים באינדקסים של IVFFlat, הפרמטר ivfflat.probes שולט בכמה מחיצות אינדקס (רשימות) מחפשים עבור כל שאילתה. ערכים גבוהים יותר מגדילים את הזיכרון (מציאת יותר מהשכנים הקרובים האמיתיים) אך שאילתות איטיות. פשרה זו היא מרכזית בכיוון הביצועים של IVFFlat. אתה מאזן בין הסיכון להחמיץ התאמות טובות לבין העלות של חיפוש בעוד מחיצות. ערך ברירת המחדל של 1 מחפש רק את המחיצה המבטיחה ביותר, שהיא מהירה אך עלולה לפספס תוצאות רלוונטיות המאוחסנות במחיצות סמוכות. למנועי המלצה שבהם פספוס התאמה טובה פוגע בחוויית המשתמש, תתחיל עם ivfflat.probes הגדרה של 5-10% מהפרמטר שלך lists ותתאם לפי החזרה המדודה.

-- Configure IVFFlat search depth
SET ivfflat.probes = 10;

-- Execute vector search
SELECT id, name, embedding <=> $1 AS distance
FROM products
ORDER BY embedding <=> $1
LIMIT 10;

עבור אינדקסים של HNSW, הפרמטר hnsw.ef_search שולט בגודל רשימת המועמדים הדינמית במהלך החיפוש. ערכים גדולים יותר חוקרים יותר את הגרף, משפרים את הקריאה במחיר של מהירות. בניגוד לחלוקות הדיסקרטיות של IVFFlat, מבנה הגרף של HNSW אומר שפרמטר זה משפיע על האופן שבו האלגוריתם חוקר לעומק את חיבורי השכנים לפני החזרת התוצאות. ערך ברירת המחדל של 40 מספק איזון סביר עבור עומסי עבודה רבים. לדרישות דיוק גבוה (כמו מציאת ההתאמות האמיתיות בטופ 10), הגדילו ל-100-200. ביישומים קריטיים להשהיה שבהם תוצאות מקובלות מקובלת, ערכים נמוכים עד 20 יכולים לעבוד. הגדר hnsw.ef_search עם SET hnsw.ef_search = 100; לפני ביצוע החיפוש הווקטורי שלך. הערך האופטימלי תלוי בדרישות הדיוק שלך ובתקציב ההשהיה שלך. בדוק עם שאלות מייצגות כדי למצוא את האיזון הנכון ליישום שלך.

מעקב ומדידת ביצועים

כיוון בלי מדידה הוא ניחוש. השתמש בכלים המובנים של PostgreSQL וב-Azure Monitor כדי להבין את התנהגות השאילתות ולאמת שינויים בתצורה.

הפקודה EXPLAIN ANALYZE מראה כיצד PostgreSQL מבצע שאילתה ומספק מידע זמני ממשי. בשאילתות וקטוריות, זה מגלה האם משתמשים באינדקסים והיכן מושקע הזמן. הבנת תוכנית הביצוע עוזרת לך לזהות האם ביצועים ירודים נובעים מאינדקסים חסרים, הגדרות פרמטרים לא מיטביות, או בעיות בחלוקת נתונים. הרץ EXPLAIN ANALYZE לפני שאילתת הווקטור שלך כדי לראות את תוכנית הביצוע. חפש סריקת אינדקס באמצעות [index_name] (מציין שהאינדקס הווקטורי בשימוש), Seq Scan (מציין סריקה רציפה, שהיא איטית לטבלאות גדולות), ערכי זמן בפועל (מראה איפה זמן הביצוע מושקע), וספירת שורות (עזרה לזהות אם הסינון עובד ביעילות). אם אתה רואה סריקות רציפות כשאתה מצפה לשימוש באינדקס, בדוק שאופרטור המרחק של השאילתה תואם למחלקת האופרטור של האינדקס (לדוגמה, באמצעות <=> אינדקס שנוצר באמצעות vector_cosine_ops).

לפעמים PostgreSQL בוחר לא להשתמש באינדקס זמין. סיבות נפוצות לשאילתות וקטוריות כוללות שאילתות שמחזירות חלק גדול מהטבלה (העומס האינדקסי עולה על סריקה רציפה), סטטיסטיקות מיושנות לאחר שינויים משמעותיים בנתונים, או אופרטור מרחק שאינו תואם למחלקת האופרטורים של האינדקס. רץ ANALYZE products; לעדכן סטטיסטיקות לתכנון מדויק. אתה יכול לבדוק את מידע האינדקס עם SELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'products';.

Azure Database for PostgreSQL חושף מדדים דרך Azure Monitor שמסייעים לזהות צווארי בקבוק בביצועים. מעקב אחרי אחוז המעבד (מעבד מתמשך גבוה מצביע על פעולות וקטוריות מחושבות), אחוז זיכרון (התקרבות למגבלות מרמזת על הגדלת רמת החישוב או אופטימיזציה של שאילתות), אחוז קלט אחסון (ערכים גבוהים מצביעים על כך שהנתונים אינם מתאימים למטמון), וחיבורים פעילים (התקרבות למגבלות מצביעה על כך שאיגוד חיבורים עשוי לעזור). הגדר התראות למדדים האלה כדי לתפוס ירידה בביצועים לפני שזה משפיע על המשתמשים.

שיטות עבודה מומלצות לכיוון pgvector

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

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

משאבים נוספים