簡體   English   中英

如何優化SQL自連接查詢?

[英]How to optimize SQL self-join query?

我有兩個表(這些是第三方應用程序的一部分,所以我無法更改它們的架構):

  • doc 有 doc_id、is_active、part_number、name 和 description
  • 節點有 node_id、doc_id 和 parent_node_id。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM