我对嵌套集结构的查询有些麻烦(~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
。
答案 0 :(得分: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
答案 1 :(得分:0)
首先,你有一个左连接加载,左连接很慢 - 我假设你正在使用它们,因为它们在这里是必要的(即连接的表可能不包含匹配,你想要返回每一行Webshop.Category,无论是否存在连接的行)。 如果没有必要左连接,我会转换为内连接。 如果左连接 是必要的,我会考虑更好的数据库设计,以消除对这些左连接的需要。这可能是不可避免的,但我会感到惊讶。
如果无法转换为内部联接,或者查询仍然很慢,那么您可以尝试首先将子查询作为insert into语句运行,创建临时表,然后使用该临时表代替sub查询(可能是连接而不是“in”)。
如果仍然很慢,您可以尝试在ID上索引该临时表。
(在上述所有情况中,我假设这些表是明智的索引?)
答案 2 :(得分: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
时,唯一可能改变速度的方法是用IN
替换EXISTS
:
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