1

我对嵌套集结构的查询遇到了一些问题,速度很慢(约 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在子查询中删除 from join 。

4

3 回答 3

0

您可以尝试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
于 2014-09-09T10:44:24.600 回答
0

首先,这里有很多左连接并且左连接很慢 - 我假设您正在使用它们,因为它们在这里是必需的(即连接的表可能不包含匹配项,并且您希望返回 Webshop.Category 的每一行无论是否存在连接行)。如果不需要左连接,我将转换为内连接。如果需要左连接我会考虑更好的数据库设计,以消除对这些左连接的需求。这可能是不可避免的,但我会感到惊讶。

如果无法转换为内部连接,或者查询仍然很慢,那么您可以尝试首先将子查询作为插入语句运行,创建一个临时表,然后使用该临时表代替子查询(可能作为一个连接而不是一个“in”)。

如果这仍然很慢,您可以尝试在 ID 上索引该临时表。

(在上述所有内容中,我假设这些表已被合理索引?)

于 2014-09-09T10:45:11.440 回答
0

您的 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

当您在子查询中替换left joins为时inner join,唯一可能改变此处速度的就是替换INEXISTS

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
于 2014-09-09T10:52:08.193 回答