【发布时间】:2012-03-21 11:29:28
【问题描述】:
简单来说,我有四个表。
ref_TagGroup (top-level descriptive containers for various tags)
ref_Tag (tags with name and unique tagIDs)
ref_Product
ref_TagMap (TagID,Container,ContainerType)
A fifth table, ref_ProductFamily exists but is not directly part of this query.
我使用 ref_TagMap 表将标签映射到产品,同时也将标签映射到 TagGroups 以及产品系列。 ContainerType 相应地设置为 PROD/TAGGROUP/PRODFAM。
所以,我想返回标签组、标签名以及标签映射到的产品和产品系列的数量......所以结果如下:
组名 |标记名 | TagHitCnt
我的问题是,为什么第一个查询以毫秒为单位返回,第二个查询以毫秒为单位返回,但第三个查询(只是添加一个“或”条件以包括标签到产品和标签到家庭映射)需要很长时间(好吧,反正超过十分钟......我还没有让它运行一整夜。)
问题 1:
SELECT ref_taggroup.groupname,ref_tag.tagname,COUNT(DISTINCT IFNULL(ref_product.familyid,ref_product.id + 100000000),ref_product.name) AS 'taghitcnt'
FROM (ref_taggroup,ref_tag,ref_product)
LEFT JOIN ref_tagmap GROUPMAP ON GROUPMAP.containerid=ref_taggroup.groupid
LEFT JOIN ref_tagmap PRODMAP ON PRODMAP.containerid=ref_product.id
WHERE
GROUPMAP.tagid=ref_tag.tagid AND GROUPMAP.containertype='TAGGROUP'
AND
PRODMAP.tagid=ref_tag.tagid AND PRODMAP.containertype='PROD'
GROUP BY tagname
ORDER BY groupname,tagname ;
问题 2:
SELECT ref_taggroup.groupname,ref_tag.tagname,COUNT(DISTINCT IFNULL(ref_product.familyid,ref_product.id + 100000000),ref_product.name) AS 'taghitcnt'
FROM (ref_taggroup,ref_tag,ref_product)
LEFT JOIN ref_tagmap GROUPMAP ON GROUPMAP.containerid=ref_taggroup.groupid
LEFT JOIN ref_tagmap PRODFAMMAP ON PRODFAMMAP.containerid=ref_product.familyid
WHERE
GROUPMAP.tagid=ref_tag.tagid AND GROUPMAP.containertype='TAGGROUP'
AND
PRODFAMMAP.tagid=ref_tag.tagid AND PRODFAMMAP.containertype='PRODFAM'
GROUP BY tagname
ORDER BY groupname,tagname ;
问题 3:
SELECT ref_taggroup.groupname,ref_tag.tagname,COUNT(DISTINCT IFNULL(ref_product.familyid,ref_product.id + 100000000),ref_product.name) AS 'taghitcnt'
FROM (ref_taggroup,ref_tag,ref_product)
LEFT JOIN ref_tagmap GROUPMAP ON GROUPMAP.containerid=ref_taggroup.groupid
JOIN ref_tagmap PRODMAP ON PRODMAP.containerid=ref_product.id
JOIN ref_tagmap PRODFAMMAP ON PRODFAMMAP.containerid=ref_product.familyid
WHERE
GROUPMAP.tagid=ref_tag.tagid AND GROUPMAP.containertype='TAGGROUP'
AND
((PRODMAP.tagid=ref_tag.tagid AND PRODMAP.containertype='PROD')
OR
(PRODFAMMAP.tagid=ref_tag.tagid AND PRODFAMMAP.containertype='PRODFAM' ))
GROUP BY tagname
ORDER BY groupname,tagname ;
-- 为了回答可能出现的问题,选择中的 COUNT Distinct ifnull 旨在为分组到系列中的大量产品返回一条记录,为不在系列中的每个“独立”产品返回一条记录.此代码在其他查询中运行良好。
我已尝试对前两个查询执行 UNION,它有效并且很快返回,但由于其他原因不实用,我不会在这里讨论。
最好的方法是什么?我做错了什么?
谢谢!
添加解释输出
QUERY1
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE GROUPMAP ALL 5640 Using where; Using temporary; Using filesort
1 SIMPLE ref_tag ref PRIMARY PRIMARY 4 lsslave01.GROUPMAP.tagid 1 Using index
1 SIMPLE ref_taggroup ref PRIMARY PRIMARY 4 lsslave01.GROUPMAP.containerid 3 Using index
1 SIMPLE PRODMAP ALL 5640 Using where; Using join buffer
1 SIMPLE ref_product eq_ref PRIMARY PRIMARY 4 lsslave01.PRODMAP.containerid 1
QUERY2
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE GROUPMAP ALL 5640 Using where; Using temporary; Using filesort
1 SIMPLE ref_tag ref PRIMARY PRIMARY 4 lsslave01.GROUPMAP.tagid 1 Using index
1 SIMPLE ref_taggroup ref PRIMARY PRIMARY 4 lsslave01.GROUPMAP.containerid 3 Using index
1 SIMPLE PRODFAMMAP ALL 5640 Using where; Using join buffer
1 SIMPLE ref_product ref FixtureType FixtureType 5 lsslave01.PRODFAMMAP.containerid 39 Using where
QUERY3
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE GROUPMAP ALL 5640 Using where; Using temporary; Using filesort
1 SIMPLE ref_tag ref PRIMARY PRIMARY 4 lsslave01.GROUPMAP.tagid 1 Using index
1 SIMPLE ref_taggroup ref PRIMARY PRIMARY 4 lsslave01.GROUPMAP.containerid 3 Using index
1 SIMPLE PRODMAP ALL 5640 Using join buffer
1 SIMPLE PRODFAMMAP ALL 5640 Using where; Using join buffer
1 SIMPLE ref_product eq_ref PRIMARY,FixtureType PRIMARY 4 lsslave01.PRODMAP.containerid 1 Using where
enter code here
为感兴趣的人提供一个更新: 我终于让上面的第三个查询运行完成。它花了大约1000秒。将此时间除以每个查询(1 或 2)运行所需的时间,我们得到一个大约 6000 的数字......这非常接近我们在开发环境中使用的 ref_tagmap 表的大小(生产量大得多)。所以,看起来我们正在针对该表中的每条记录运行一个查询......但我仍然不明白为什么。
任何帮助将不胜感激......我的意思是认真,非常感谢。
【问题讨论】:
-
在每个查询前加上
EXPLAIN会得到什么?你能告诉我们CREATE TABLE的输出吗?为什么要混合连接语法? -
我为三个查询中的每一个附加了解释输出。您需要为哪些表创建?它们非常简单......我认为问题在于我如何在第三个查询中使用“OR”子句......那里有任何指导吗?至于 LEFT JOINS 和 JOINS 的用户,这就是我最终的结果……我尝试了多种组合。当然,我不是 sql 天才。
-
尝试将 Query3 重写为 Union。
-
索引连接条件中使用的列
-
ypercube,我已经做到了,它按预期加快了速度,但由于解释的其他原因,我不能在这段代码中使用联合。
标签: mysql join multiple-tables