簡體   English   中英

使用“ in”緩慢的帶有聯接和子查詢的SQL嵌套集查詢

[英]SQL Nested set query with join and sub query using “in” slow

我在慢速(〜4秒)的嵌套集結構上進行查詢時遇到了一些麻煩

select node.ID, node.Lft, node.Rgt, node.Level, count(ag.ArticleID) as count
from Webshop.Category node
left join Webshop.Category parent on parent.Lft between node.Lft and node.Rgt
left join Webshop.ArticleGroup ag on parent.GroupID = ag.GroupID
    and ag.ArticleID in (
        select a.ID
        from Webshop.Article a
        join Webshop.ArticleOwner ao on ao.ArticleID = a.ID and ao.OWNRID = 1
        join Webshop.ArticleAssortment aa on aa.ArticleID = a.ID and aa.AssortmentID = 6
    )
group by node.ID
having count > 0

說明返回以下內容:

id,select_type,table,type,possible_keys,key,key_len,ref,rows,Extra
1,PRIMARY,node,ALL,NULL,NULL,NULL,NULL,2538,"Using temporary; Using filesort"
1,PRIMARY,parent,ALL,Lft,NULL,NULL,NULL,2538,
1,PRIMARY,ag,ref,fk_ArticleGroup_Group1_idx,fk_ArticleGroup_Group1_idx,4,Webshop.parent.GroupID,9,"Using index"
2,"DEPENDENT SUBQUERY",a,eq_ref,PRIMARY,PRIMARY,4,func,1,"Using index"
2,"DEPENDENT     SUBQUERY",ao,eq_ref,"ArticleIDOWNRID,fk_ArticleOwner_Article1_idx,fk_ArticleOwner_OWNR1_idx",ArticleI    DOWNRID,8,"Webshop.a.ID,const",1,"Using index"
2,"DEPENDENT SUBQUERY",aa,eq_ref,"PRIMARY,fk_ArticleAssortment_Article1_idx",PRIMARY,8,"Webshop.a.ID,const",1,"Using index"

我認為使用in()的子查詢會使查詢變慢。 有一個更好的方法嗎?

謝謝。

編輯:

我忘記了從子查詢中的聯接中刪除left

您可以嘗試JOIN

select node.ID, node.Lft, node.Rgt, node.Level, count(ag.ArticleID) as count
from Webshop.Category node
left join Webshop.Category parent on parent.Lft between node.Lft and node.Rgt
left join Webshop.ArticleGroup ag on parent.GroupID = ag.GroupID
        join (
        select a.ID as `id`
        from Webshop.Article a
        left join Webshop.ArticleOwner ao on ao.ArticleID = a.ID and ao.OWNRID = 1
        left join Webshop.ArticleAssortment aa on aa.ArticleID = a.ID and aa.AssortmentID = 6
    ) in_ids on ag.ArticleID = in_ids.id
group by node.ID
having count > 0

首先,您在這里有大量的左聯接,並且左聯接很慢-我假設您正在使用它們,因為這里需要它們(即聯接的表可能不包含匹配項,並且您想返回Webshop的每一行。不論是否存在連接的行)。 如果不需要左聯接,我將轉換為內部聯接。 如果需要左連接我會考慮更好的數據庫設計,以消除對這些左連接的需求。 這可能是不可避免的,但我會感到驚訝。

如果無法轉換為內部聯接,或者查詢仍然很慢,則可以嘗試先將子查詢作為插入語句運行,創建一個臨時表,然后使用該臨時表代替子查詢(可能是作為聯接而不是“ in”)。

如果仍然很慢,則可以嘗試在ID上索引該臨時表。

(在以上所有情況下,我都假定對表進行了合理索引?)

您的IN子查詢包含不影響結果的LEFT JOIN子句,因此首先您可以將其更改為:

select node.ID, node.Lft, node.Rgt, node.Level, count(ag.ArticleID) as count
from Webshop.Category node
left join Webshop.Category parent on parent.Lft between node.Lft and node.Rgt
left join Webshop.ArticleGroup ag on parent.GroupID = ag.GroupID
    and ag.ArticleID in (
        select a.ID
        from Webshop.Article a
    )
group by node.ID
having count > 0

現在,完成此操作后,我們可以看到您正在檢查AritcleID外鍵的一致性。 因此,有兩種選擇。 首先,有一個外鍵,您不必擔心,完全刪除IN

select node.ID, node.Lft, node.Rgt, node.Level, count(ag.ArticleID) as count
from Webshop.Category node
left join Webshop.Category parent on parent.Lft between node.Lft and node.Rgt
left join Webshop.ArticleGroup ag on parent.GroupID = ag.GroupID
group by node.ID
having count > 0

第二種選擇,您沒有外鍵。 創建一個不是一個壞主意。

更新:我剛剛注意到查詢的末尾有count > 0 ,這意味着您可以將所有left join子句替換為具有相同結果的inner join

在子查詢中用inner join left joins替換left joins ,唯一可能改變速度的是用EXISTS代替IN

select node.ID, node.Lft, node.Rgt, node.Level, count(ag.ArticleID) as count
from Webshop.Category node
inner join Webshop.Category parent on parent.Lft between node.Lft and node.Rgt
inner join Webshop.ArticleGroup ag on parent.GroupID = ag.GroupID
WHERE EXISTS (
    SELECT * FROM
        from Webshop.Article a
        join Webshop.ArticleOwner ao on ao.ArticleID = a.ID and ao.OWNRID = 1
        join Webshop.ArticleAssortment aa on aa.ArticleID = a.ID and aa.AssortmentID = 6 
    WHERE a.ID = ag.ArticleID
    )
group by node.ID
-- you don't need HAVING clause here

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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