שיטות מומלצות לשאילתות גרפים
במאמר הזה מתוארות שיטות מומלצות לאופטימיזציה של שאילתות גרף ב-BigQuery.
התחלת Path traversal מצמתים עם קרדינליות נמוכה
כדי לשמור על קבוצות קטנות של תוצאות ביניים ולזרז את הביצוע של שאילתות, כדאי לכתוב את שאילתות הגרף כך ש-Path traversal יתחיל מצמתים עם קרדינליות נמוכה, בלי קשר לכיוון של Path traversal. ההצהרות הבאות של MATCH משתמשות במסנני מאפיינים כדי לצמצם את מספר צמתי ההתחלה האפשריים, במקום לחשב את כל ההתאמות ואז לסנן:
MATCH (p:Person {id: 10})-[own:Owns]->(a:Account)
MATCH (a:Account WHERE balance > 10)<-[own:Owns]-(p:Person)
זה חשוב במיוחד לשאילתות של נתיבים כמותיים:
MATCH (p:Person {id: 10})-[own:Owns]->{1,3}(a:Account)
שימוש בתחביר ANY או ANY SHORTEST לבדיקות קישוריות
שאילתות של מסלולים עם ערכים כמותיים יכולות להחזיר מסלולים כפולים בין צמתי מקור לצמתי יעד. אם המטרה שלכם היא לבדוק את הקישוריות ואתם לא צריכים את כל הנתיבים האפשריים, כדאי להשתמש ב-ANY או ב-ANY SHORTEST כדי לצמצם את החישובים המיותרים ולשפר את היעילות של חיפוש הנתיבים. לדוגמה, ההצהרה MATCH הבאה משתמשת ב-ANY SHORTEST כדי להשאיר רק נתיב אחד בין כל זוג צמתים:
MATCH ANY SHORTEST (a1:Account)-[t:Transfers]->{1,3}(a2:Account)
שימוש ב-Path traversal כיווני
סכימות של BigQuery Graph הן כיווניות, כלומר לכל קצה יש צומת מקור וצומת יעד. למרות שתחביר השאילתה של הגרף מאפשר מעבר נתיבים בכל כיוון (לדוגמה, -[edge]-), מומלץ להשתמש במעבר נתיבים חד-כיווני (לדוגמה, -[edge]-> או <-[edge]-) כדי לשפר את הביצועים. מעבר בין נתיבים בכל כיוון עלול לגרום לירידה בביצועים.
ההצהרה הבאה MATCH משתמשת בנתיב מעבר בכל כיוון:
-- Avoid.
MATCH (a1:Account {id: 7})-[t:Transfers]-(a2:Account)
במקום זאת, משלבים בין שני מעברים בכיוונים שונים באמצעות UNION ALL:
MATCH (a1:Account {id: 7})-[t:Transfers]->(a2:Account)
...
UNION ALL
...
MATCH (a1:Account {id: 7})<-[t:Transfers]-(a2:Account)
ציון תוויות באופן מפורש
אם לא מציינים תוויות של צמתים או קשתות בשאילתה, BigQuery Graph מפרט את כל התוויות הרלוונטיות של צמתים וקשתות. יכול להיות שהספירה הזו תגרום לסריקה של יותר תוויות מהנדרש. כדי למנוע את זה, כדאי לציין תוויות לכל הצמתים והקצוות בשאילתה, אם אפשר.
לדוגמה, השאילתה הבאה מציינת את התוויות Account ו-Transfers:
GRAPH graph_db.FinGraph
MATCH (a1:Account)-[t:Transfers]->(a2:Account)
RETURN COUNT(*) AS num_transfers;
לא כדאי להשמיט תוויות, כי יכול להיות שהסריקה תכלול קשרים אחרים בין צמתים שלא צריך. בשאילתה הבאה, a1 יכול לייצג חשבון או אדם, ו-t יכול לייצג העברה או בעלות על חשבון.
GRAPH graph_db.FinGraph
MATCH (a1)-[t]->(a2)
RETURN COUNT(*) AS num_transfers;
העדפה של הצהרת MATCH אחת
בעזרת BigQuery Graph אפשר לכלול כמה הצהרות MATCH בשאילתת גרף אחת. המשפטים האלה מקושרים באמצעות משתנים שהוגדרו כמה פעמים ומייצגים את אותו צומת או קצה. עם זאת, שימוש בכמה הצהרות MATCH
עלול להפחית את היתרונות של הקרדינליות בין ההצהרות. כשאפשר, כדאי להשתמש בהצהרת MATCH אחת כדי לשפר את הביצועים.
לדוגמה, השאילתות הבאות שקולות, אבל הראשונה מבצעת את הפעולה טוב יותר כי היא משתמשת בהצהרת MATCH אחת:
-- Preferred syntax.
GRAPH graph_db.FinGraph
MATCH
(p:Person {id: 1})-[o:Owns]->
(a:Account)-[t:Transfers]->(a2:Account)
RETURN o.account_id, t.amount;
-- Avoid this syntax.
GRAPH graph_db.FinGraph
MATCH (p:Person {id: 1})-[o:Owns]->(a:Account)
MATCH (a:Account)-[t:Transfers]->(a2:Account)
RETURN o.account_id, t.amount;
הגבלת הקצוות שעוברים מצמתים עם עוצמה גבוהה
כששולחים שאילתות לגרפים, יכול להיות שלחלק מהצמתים יהיה מספר גדול משמעותית של קשתות נכנסות או יוצאות בהשוואה לצמתים אחרים. לפעמים הצמתים האלה עם הקרדינליות הגבוהה נקראים צמתים ראשיים או צמתים מרכזיים. צמתים ראשיים עלולים לגרום לבעיות בביצועים כי מעבר דרכם עשוי לכלול עיבוד של כמויות גדולות של נתונים, מה שמוביל לחלוקת נתונים לא מאוזנת (partition skew) ולזמני ביצוע ארוכים.
כדי לבצע אופטימיזציה של שאילתה של תרשים עם צמתים ראשיים, משתמשים בפונקציה ROW_NUMBER() בתוך פסקה FILTER או פסקה WHERE ב-MATCH כדי להגביל את מספר הקצוות שהשאילתה עוברת מצומת או לצומת. הטכניקה הזו שימושית במיוחד כשלא צריך ספירה מלאה של כל החיבורים מצומת-על או אליו.
לדוגמה, אם בחלק מהחשבונות ב-FinGraph יש מספר גדול של טרנזקציות, אפשר להשתמש ב-ROW_NUMBER() כדי להגביל את מספר הקצוות Transfers שייכללו בכל Account וכך להימנע משאילתה לא יעילה:
GRAPH graph_db.FinGraph
MATCH (a1:Account)-[e1:Transfers WHERE e1 IN {
GRAPH graph_db.FinGraph
-- Sample 5 edges per source node
MATCH -[selected_e:Transfers]->
FILTER ROW_NUMBER() OVER (
PARTITION BY SOURCE_NODE_ID(selected_e)) < 5
RETURN selected_e
}]->{1,3}(a2:Account)
RETURN COUNT(*) AS cnt;
דוגמה לצמתים או לקצוות ביניים בשאילתות עם כמה קפיצות
אפשר גם לשפר את יעילות השאילתות באמצעות ROW_NUMBER() כדי לדגום צמתים ביניים בשאילתות מרובות קפיצות. הטכניקה הזו משפרת את היעילות על ידי הגבלת מספר הנתיבים שהשאילתה בודקת עבור כל צומת ביניים. כדי לעשות את זה, צריך לחלק שאילתה עם כמה קפיצות למספר משפטי MATCH שמופרדים באמצעות NEXT, ולהחיל ROW_NUMBER() באמצע, במקום שבו רוצים לבצע דגימה:
GRAPH graph_db.FinGraph
MATCH (a1:Account)-[e1:Transfers]->(a2:Account)
-- Sample 5 destination nodes per a1 source node
FILTER ROW_NUMBER() OVER (PARTITION BY ELEMENT_ID(a1)) < 5
RETURN a1, a2
NEXT
MATCH (a2)-[e2:Transfers]->(a3:Account)
RETURN a1.id AS src_id, a2.id AS mid_id, a3.id AS dst_id;
המאמרים הבאים
- מידע נוסף על כתיבת שאילתות לגרפים זמין במאמר סקירה כללית של שאילתות.
- מידע נוסף על עיצוב סכימת הגרף