本文提供撰寫 GQL(圖查詢語言)查詢的指導,這些查詢在 Microsoft Fabric 中處理圖形時能有可預測且有效率地執行。 這些建議是根據目前平台的行為和文件上的限制條件提出的。
關於圖大小、結果大小及查詢逾時的硬性限制,請參見 「目前限制」。 本文中也有幾項建議與你如何設計圖結構有關。 欲了解更多資訊,請參見 「設計圖結構」。
根據語意放置篩選器
當述詞用來定義哪些節點或邊可以參與比對時,請將其放在圖樣內。 使用陳述式層級的 MATCH ... WHERE 條件來後置篩選已完成的比對,或當謂詞適用於較早前的陳述式所產生的資料列時,使用個別的 FILTER 陳述式。
例如,針對相符節點的條件,使用模式層級的 WHERE 子句:
MATCH (p:Person WHERE p.birthday < 19940101)-[:workAt]->(c:Company WHERE c.id > 1000)
RETURN p.firstName, p.lastName, c.name
獨立的 FILTER 也可以在使用預設 ALL 路徑搜尋的一般必要比對之後,表達相同的條件:
MATCH (p:Person)-[:workAt]->(c:Company)
FILTER p.birthday < 19940101 AND c.id > 1000
RETURN p.firstName, p.lastName, c.name
查詢優化器可在掃描期間套用等效的謂詞,只要這麼做不會改變查詢語意,因此內嵌語法本質上未必更快。 選擇能表達條件適用時間的形式。
謂詞的擺放可能會影響使用 ANY SHORTEST 時的結果。 內聯謂詞限制了可選擇最短路徑的路徑。 陳述式層級的 WHERE 或後續的 FILTER 會在路徑選取之後套用,因此它可以移除已選取的最短路徑,卻不會改為選取較長的路徑。 關於目前 MATCH ... WHERE 的限制與可靠的擺放模式,請參見「 路徑選擇前或後的置位謂詞」。
放置位置同樣很重要:在 OPTIONAL MATCH 中,內嵌的 WHERE 會限制選用的比對,但後續的 FILTER 則可移除經空值擴展的資料列。
小提示
可將模式層 WHERE 視為 SQL JOIN ... ON 條件。 它描述哪些配對符合資格,而非事後過濾結果的列。
只回傳你需要的屬性
只回傳你情境所需的節點和邊緣屬性。 避免回傳完整節點或在只需部分屬性的情況下使用RETURN *。
選擇不必要的屬性會增加資料讀取、序列化成本及響應大小。 在圖建模時,只選擇你需要作為節點類型屬性的來源欄位。
建議: 窄投射。
MATCH (p:Person)-[:workAt]->(c:Company)
RETURN p.firstName, p.lastName, c.name
避免: 回傳全結點。
MATCH (p:Person)-[:workAt]->(c:Company)
RETURN *
備註
只有在圖建模時,當需要用於查詢或分析時,才會加入節點類型的屬性。 每個節點的屬性數量減少時,能同時降低儲存和查詢的負擔。
結果集大小限制
查詢可能基數高的節點或關係時,應用 LIMIT 或其他限制條件。 無界圖匹配能產生非常龐大的結果集,接近平台極限。
推薦: 結果有界。
MATCH (p:Person)-[:knows]->(friend:Person)
RETURN p.firstName, friend.firstName
LIMIT 1000
避免: 無界高基數匹配。
MATCH (p:Person)-[:knows]->(friend:Person)
RETURN p.firstName, friend.firstName
這很重要
Graph 會截斷其內部二進位表示超過 64 MB 的查詢回應。 簡短回應包含一個附加的狀態,包含公共代碼 01000 及標準的 GQLSTATUS 01M11。 使用濾鏡、窄投影,並 LIMIT 縮小結果大小。 如需詳細資訊,請參閱目前的限制。
保持遍歷淺且具針對性
避免深度巢式或高度複雜的圖型態。 使用簡單且有針對性的遍歷,直接回答特定問題。 在可變長度模式中,每多跳一次,引擎評估的路徑數量都會呈指數增加,尤其是在密集連結的圖中。
推薦: 緊密的限制。
-- Use the narrowest hop range that answers your question
MATCH (p:Person)-[:knows]->{1,3}(friend:Person)
RETURN p.firstName, friend.firstName
LIMIT 1000
避免: 在沒有明確需求的情況下使用過大的遍歷範圍。
-- A wider range on a dense graph is more expensive
MATCH (p:Person)-[:knows]->{1,8}(friend:Person)
RETURN *
這很重要
視覺化查詢建構器限制可變長度路徑為八跳,但這個使用者介面限制不適用於程式碼編輯器中的 GQL。 用你情境允許的最嚴格的範圍,因為更寬的範圍可以匹配更多路徑。
當路徑不能重複邊緣時,請使用 TRAIL
當合法路徑不得重複任何邊時,請使用 TRAIL 路徑模式。 在有循環的圖中,此限制也可能減少相較於預設 WALK 模式的匹配路徑數量。
-- TRAIL prevents revisiting the same :knows edge
MATCH TRAIL (src:Person)-[:knows]->{1,4}(dst:Person)
WHERE src.firstName = 'Alice' AND dst.firstName = 'Bob'
RETURN count(*) AS numPaths
若沒有 TRAIL,循環圖上的相同查詢可以返回重複一條邊的路徑。 請使用符合所需路徑語意的模式,而不要將 TRAIL 視為一般的效能優化。
無界 ALL WALK 模式不被支援,因為循環可以產生無限多條路徑。 雖然 TRAIL、SIMPLE 和 ACYCLIC 這些無界模式會終止,但仍可能列舉出許多路徑。 除非查詢需要進行無界遍歷,否則應使用有限上界。
使用共享變數來促進有效率的連接
當查詢需要來自多個關係的資料時,使用共享變數將模式連結在同一實體上。 若沒有共享變數,模式可能會產生笛卡兒積——即兩種模式的匹配組合——進而產生更大的結果集。
推薦閱讀: 共享變數 p 會加入這些模式。
-- Single shared variable ensures an efficient join
MATCH (p:Person)-[:workAt]->(c:Company),
(p)-[:isLocatedIn]->(city:City)
RETURN p.firstName, c.name AS company, city.name AS city
LIMIT 1000
避免: 獨立的模式,沒有共享變數。
-- Without a shared variable, this produces a cartesian product
MATCH (p1:Person)-[:workAt]->(c:Company),
(p2:Person)-[:isLocatedIn]->(city:City)
RETURN p1.firstName, c.name, p2.firstName, city.name
笛卡兒積會將一個圖案的每個結果與另一個圖案的結果配對。 若 Person-workAt->Company 匹配 1,000 列且 Person-isLocatedIn->City 匹配 500 列,查詢回傳 1,000 × 500 = 500,000 列。 加入共享變數會限制連接,因此只會回傳匹配的變數對。
在識別節點時,依據關鍵屬性進行篩選
定義 節點金鑰限制 ,以唯一識別節點並強制資料完整性。 當你需要某個特定節點時,可以在模式謂詞中包含其金鑰屬性,以避免匹配到無關的節點。
例如,如果你的圖型別定義 id 作為節點的鍵 Person。
CONSTRAINT person_pk
FOR (n:Person) REQUIRE n.id IS KEY
然後在你需要找那個人時,依 id 篩選:
MATCH (p:Person WHERE p.id = 12345)-[:workAt]->(c:Company)
RETURN p.firstName, c.name
若沒有篩選條件,查詢會先比對所有 Person 節點,再遍歷 workAt 邊:
MATCH (p:Person)-[:workAt]->(c:Company)
RETURN p.firstName, c.name
小提示
一個關鍵限制是確立身份與唯一性。 它本身並不保證特定的實體搜尋或查詢計畫。
選擇適當的數據類型
選擇代表每個屬性值與預期操作的資料型態。 例如,使用數值類型來計算或比較數值,而不是將格式化的數字儲存成字串。
關於支援的資料型態,請參見 「目前限制 — 資料型別 」及 「支援屬性型別」。
將相關遍歷合併於單一查詢中
若可能,請以單一圖模式檢索相關實體,而非分別發出獨立遍歷相同邊的查詢。 結合遍歷可避免冗餘的模式匹配,並避免 N+1 查詢問題,即一次初始查詢觸發每個結果列的獨立查詢。
推薦:單一組合圖案。
MATCH (c:Customer)-[:purchases]->(o:`Order`)-[:`contains`]->(product:`Product`)
RETURN c.fullName, o, product.productName
LIMIT 1000
避免: 兩個獨立的查詢,穿越相同的 Customer → Order 邊。
-- Query 1: fetch 100 orders
MATCH (c:Customer)-[:purchases]->(o:`Order`)
RETURN c.fullName, o
LIMIT 100
-- Query 2: repeat for each returned order, substituting its key value
MATCH (o:`Order` WHERE o.SalesOrderDetailID_K = 12345)-[:`contains`]->(product:`Product`)
RETURN o, product.productName
針對現實資料量進行測試查詢
在小型資料集上表現良好的查詢,可能無法線性擴展。 用代表預期生產工作負載的資料量來測試你的查詢。
- 偏好包含篩選條件與限制的保守查詢格式。
- 避免對大型圖表進行探索性的「回傳全部」查詢。
- 監控查詢的持續時間與 20 分鐘超時限制的關係。