我实际上已经设法让这个工作,但是想知道是否有任何Guru可能能够提供更优化的方法:
SELECT `cfc`.`card_face_id`
FROM `card_face_color` AS `cfc`
INNER JOIN `color` AS `c` ON c.color_id = cfc.color_id
WHERE c.c_url IN ('black', 'blue')
AND card_face_id NOT IN (
SELECT `cfc`.`card_face_id`
FROM `card_face_color` AS `cfc`
INNER JOIN `color` AS `c` ON cfc.color_id = c.color_id
WHERE c.c_url NOT IN ('black', 'blue')
)
GROUP BY `cfc`.`card_face_id`
HAVING (COUNT(DISTINCT c.c_url) = 2)
基本上我正在尝试选择包含黑色和蓝色的所有card_faces,但没有其他颜色(每个card_face可能最多为5个)。尝试使用内连接来做它,但这慢了近25倍。我对我的索引感到非常满意,我只是熟悉了Having子句。
更新
针对查询运行EXPLAIN
会显示此信息(对格式化道歉)。
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY c index PRIMARY,c_url c_url 50 NULL 10 Using where; Using index; Using temporary; Using filesort
1 PRIMARY cfc ref color_id color_id 1 site.co.uk.c.color_id 1156 Using where; Using index
2 SUBQUERY c range PRIMARY,c_url c_url 50 NULL 9 Using where; Using index
2 SUBQUERY cfc ref color_id color_id 1 site.co.uk.c.color_id 1156 Using index
答案 0 :(得分:1)
这是另一种方法。我首先尝试将结果集限制为只有2种颜色的卡片面。如果表现更好,请告诉我。
SELECT cfc2.card_face_id, COUNT(*) AS cardcount2
FROM card_face_color cfc2
INNER JOIN color c ON cfc2.color_id=c.color_id AND c.c_url IN ('black','blue')
INNER JOIN (SELECT cfc.card_face_id, COUNT(*) AS cardcount
FROM card_face_color cfc
GROUP BY cfc.card_face_id
HAVING cardcount=2) AS color_counter ON cfc2.card_face_id=color_counter.card_face_id
GROUP BY cfc2.card_face_id
HAVING cardcount2=2
APPROACH 2
另一种离墙式方法:
SELECT card_face_id, SUM(U.counter) AS counter FROM
(
SELECT cfc2.card_face_id, 1 AS counter
FROM card_face_color cfc2
INNER JOIN color c ON cfc2.color_id=c.color_id AND c.c_url IN ('black','blue')
UNION ALL
SELECT cfc2.card_face_id, 100 AS counter
FROM card_face_color cfc2
INNER JOIN color c ON cfc2.color_id=c.color_id AND NOT c.c_url IN ('black','blue')
) AS U
GROUP BY card_face_id
HAVING counter=2
APPROACH 3 我不确定你有多灵活,但在这种方法中我消除了内连接:
SET @blue_id = (SELECT color_id FROM color WHERE c_url='blue');
SET @black_id = (SELECT color_id FROM color WHERE c_url='black');
SELECT card_face_id, SUM(U.counter) AS counter FROM
(
SELECT cfc2.card_face_id, 1 AS counter
FROM card_face_color cfc2
WHERE cfc2.color_id IN (@blue_id,@black_id)
UNION ALL
SELECT cfc2.card_face_id, 100 AS counter
FROM card_face_color cfc2
WHERE cfc2.color_id NOT IN (@blue_id,@black_id)
) AS U
GROUP BY card_face_id
HAVING counter=2
答案 1 :(得分:1)
以下是查询的几个版本
这是好还是坏? (〜30毫秒)
按group_concat过滤
SELECT `cfc`.`card_face_id`
FROM `card_face_color` AS `cfc`
INNER JOIN `color` AS `c` ON c.color_id = cfc.color_id
GROUP BY `cfc`.`card_face_id`
HAVING GROUP_CONCAT(c.c_url ORDER BY c.c_url) = 'black,blue'
这可能更好地使用指数(~35ms)
好= 2,坏= 0
SELECT `cfc`.`card_face_id`
FROM `card_face_color` AS `cfc`
INNER JOIN `color` AS `c` ON c.color_id = cfc.color_id
GROUP BY `cfc`.`card_face_id`
HAVING
SUM(IF(c.c_url IN ('black','blue'), 1, NULL)) = 2 AND
SUM(IF(c.c_url IN ('black','blue'), NULL, 1)) = 0
作为第二个游戏,我这次再次尝试使用DISTINCT(约34ms)
总计= 2且良好= 2
SELECT `cfc`.`card_face_id`
FROM `card_face_color` AS `cfc`
INNER JOIN `color` AS `c` ON c.color_id = cfc.color_id
GROUP BY `cfc`.`card_face_id`
HAVING
COUNT(DISTINCT c.c_url) = 2 AND
COUNT(DISTINCT IF(c.c_url IN ('black','blue'), c.c_url, NULL)) = 2
让我们再扭一点,
总计= 2且坏= 0
SELECT `cfc`.`card_face_id`
FROM `card_face_color` AS `cfc`
INNER JOIN `color` AS `c` ON c.color_id = cfc.color_id
GROUP BY `cfc`.`card_face_id`
HAVING
COUNT(DISTINCT c.c_url) = 2 AND
COUNT(IF(c.c_url IN ('black','blue'), NULL, c.c_url)) = 0
只是为了测试所有的合并,
好= 2,坏= 0
SELECT `cfc`.`card_face_id`
FROM `card_face_color` AS `cfc`
INNER JOIN `color` AS `c` ON c.color_id = cfc.color_id
GROUP BY `cfc`.`card_face_id`
HAVING
COUNT(DISTINCT IF(c.c_url IN ('black','blue'), c.c_url, NULL)) = 2 AND
COUNT(IF(c.c_url IN ('black','blue'), NULL, c.c_url)) = 0