2010-08-30 104 views
2

我在查询时遇到了问题。我试过子查询,不同的连接和group_concat(),但它们要么不工作要么很痛苦。这可能有点复杂的解释,但这里的问题:mysql select - 子查询,group_concat()不工作/太慢

我有一个表“项目”(约2000产品)。我有一个表“标签”(其中包含大约2000个不同的产品标签)。我有一个“tagassign”表(将标签连接到项目,大约有200000条记录)。

我使用标签来定义产品的特征,例如颜色,兼容性,产品是否特价等。现在,如果我希望能够显示分配有特定标签的产品他们,我使用一个简单的查询,如:

select * from item, tagassign 
    where item.itemid = tagassign.itemid 
    and tagassign.tagid = "specialoffer" 

问题是,我可能想看到有几个标签的项目。例如,我可能只想看到与Apple iPhone兼容的黑色手机外壳,并且是新的。所以我基本上希望看到项目表中的所有记录都有“黑色”和“大小写”,“iphone”和“新”的标签。唯一可以实现这个功能的方法是创建4个别名(select * from item,tagassign,tagassign as t1,tagassign as t2,tagassign as t3等)。在某些情况下,我可能会寻找10或20个不同的标签,并且有很多记录,查询速度非常慢。

我知道我错过了一些明显的东西。有任何想法吗? 谢谢!

+0

向我们展示您的'EXPLAIN SELECT' - 索引? – Piskvor 2010-08-30 21:03:49

回答

3
SELECT * 
FROM item i 
WHERE (
     SELECT COUNT(*) 
     FROM tagassign ta 
     WHERE ta.tagid IN ('black', 'case', 'iphone', 'new') 
       AND ta.itemid = i.itemid 
     ) = 4 

用您正在搜索的标签的实际数量而不是4替代。

tagassign (itemid, tagid)(按此顺序)上创建一个唯一索引或主键,以便快速工作。

如果您正在寻找大量的标签(或很少使用的标签),此查询也更快:

SELECT i.* 
FROM (
     SELECT itemid 
     FROM tagassign ta 
     WHERE ta.tagid IN ('black', 'case', 'iphone', 'new') 
     GROUP BY 
       itemid 
     HAVING COUNT(*) = 4 
     ) t 
JOIN item i 
ON  i.itemid = t.itemid 

对于此查询,则需要在tagassign (tagid, itemid)唯一索引。

+0

对语法选择感到好奇 - 为什么不使用EXISTS并指定'HAVING COUNT(DISTINCT ta.tagid)= 4'?当我发表评论时,它不在那里,我发誓... – 2010-08-30 21:10:46

+0

@OMGPonies:由于索引是唯一的,所以'COUNT(*)'只会计算匹配记录,每个记录一次。 “EXISTS”在那里会过度杀伤。不过,为了完整起见,我会对它做出回应:) – Quassnoi 2010-08-30 21:14:32

+0

+1:我错过了第一个选项 – 2010-08-30 21:18:42