[英]How to optimize SQL self-join query?
我有兩個表(這些是第三方應用程序的一部分,所以我無法更改它們的架構):
node.doc_id 指的是一個 doc.doc_id 值(沒有外鍵關系),node.parent_node_id 指的是一個 node.node_id 值,建立 doc 表中值的父/子關系。 doc 表中的每個條目可以有零個或一個父項,以及任意數量的子項。
對於給定的部件號,我需要 doc 表中所有匹配條目的名稱和描述,並且(這是棘手的部分)對於每個這樣的匹配條目,我需要知道該條目是否有任何活動的子條目。
下面是一個例子:
doc
doc_id is_active part_number name description
1 T AAA Fred Little
2 T AAA George Middle
3 T AAA Sam Morse
4 T CCC Mary Moo
5 T DDD Carol Smith
6 F DDD Midge Moo
node
node_id doc_id parent_node_id
10 1 null
11 2 null
12 3 null
13 4 10
14 5 10
15 6 11
所以你可以看到 doc_id 1 有 2 個孩子(doc_ids 4 和 5),doc_id 2 有一個孩子(doc_id 6)。
圖形化:
doc[doc_id=1] -> 節點[doc_id=1,node_id=10]; parent_node_id=10 的節點是 node[node_id=13,doc_id=4] 和 node[node_id=14,doc_id=5]; doc[doc_id=4] 和 doc[doc_id=5] 都有 is_active=T。
doc[doc_id=2] -> 節點[doc_id=2,node_id=11]; parent_node_id=11 的唯一節點是 node[node_id=15,doc_id=6] 但 doc[doc_id=6] 有 is_active=F。
如果我請求 part_number=AAA,我需要返回:
doc_id name description has_active_children
1 Fred Little T
2 George Middle F
3 Sam Morse F
現在我有這個查詢,我計算孩子的數量(這是不必要的,但我唯一能弄清楚的):
select d1.*,
(select count(dn.node_id) from node dn
inner join doc dc on dn.doc_id=dc.doc_id
where dn.parent_node_id=
(select dx.node_id from node dx where dx.doc_id=d1.doc_id)
and dc.is_active='T') as childCount
from doc d1 where d1.part_number='AAA'
這有效,但不是非常快。 我們在 SQL Server 上運行,我嘗試了“set showplan_all”,但對輸出的理解不夠好,無法進行任何更改。
有沒有明顯更好的方法來執行此查詢? 或者,是否有文檔可以幫助我理解 showplan 輸出?
這應該是一個不錯的起點。 我不得不在一個包含地理區域分層表示的數據庫中進行類似的自連接。
如果您將 2 個left join
語句中的任何一個更改為 simple join
,則任何沒有子級的父級都將從查詢結果中刪除。
SELECT parent.[doc_id],
parent.[name],
parent.[description],
parent.[part_number],
CASE WHEN COUNT(child.[doc_id]) > 0 THEN 'T' ELSE 'F' END
FROM doc parent
JOIN node parentRef on parent.[doc_id] = parentRef.[doc_id]
LEFT JOIN node childRef on parentRef.[node_id] = childRef.[parent_node_id]
LEFT JOIN doc child on child.[doc_id] = childRef.[doc_id]
WHERE parent.[part_number] = 'AAA'
GROUP BY parent.[doc_id], parent.[name], parent.[part_number], parent.[description]
編輯:將 part_number 添加到查詢中
此外,與任何 SQL 查詢一樣,查看這些表上存在的索引。 您可以添加一兩個索引來提高查詢性能。
您可以使用非常適合您的情況的窗口函數。
SELECT parent.[doc_id],
parent.[name],
parent.[description],
parent.[part_number],
CASE WHEN ROW_NUMBER(PARTITION BY child.[doc_id]) > 0 THEN 'T' ELSE 'F' END AS childCount
FROM doc parent
JOIN node parentRef on parent.[doc_id] = parentRef.[doc_id]
LEFT JOIN node childRef on parentRef.[node_id] = childRef.[parent_node_id]
LEFT JOIN doc child on child.[doc_id] = childRef.[doc_id]
WHERE parent.[part_number] = 'AAA' AND child.is_active = 'T'
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.