我有三张桌子
filters (id, name)
items(item_id, name)
items_filters(item_id, filter_id, value_id)
values(id, filter_id, filter_value)
项目中约有20000个条目。 items_filters中约有80000个条目。
SELECT i.*
FROM items_filters itf INNER JOIN items i ON i.item_id = itf.item_id
WHERE (itf.filter_id = 1 AND itf.value_id = '1')
OR (itf.filter_id = 2 AND itf.value_id = '7')
GROUP BY itf.item_id
WITH ROLLUP
HAVING COUNT(*) = 2
LIMIT 0,10;
当条目匹配查询时为0.008时,没有条目匹配时为0.05。
之前我尝试过不同的变体:
SELECT * FROM items WHERE item_id IN (
SELECT `item_id`
FROM `items_filters`
WHERE (`filter_id`='1' AND `value_id`=1)
OR (`filter_id`='2' AND `value_id`=7)
GROUP BY `item_id`
HAVING COUNT(*) = 2
) LIMIT 0,6;
当没有条目时,这会完全冻结mysql。
我真的没有得到的是 选择我。* FROM items_filters itf INNER JOIN items i ON i.item_id = itf.item_id WHERE itf.filter_id = 1 AND itf.value_id ='1'LIMIT 0,1 没有条目时需要〜0.05,
时需要~0.008解释
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
| 1 | SIMPLE | i | ALL | PRIMARY | NULL | NULL | NULL | 10 | Using temporary; Using filesort |
| 1 | SIMPLE | itf | ref | item_id | item_id | 4 | ss_stylet.i.item_id | 1 | Using where; Using index |
答案 0 :(得分:0)
对我来说,这看起来像是四张桌子。
对查询执行EXPLAIN PLAN并查找TABLE SCAN。如果您看到一个,请在WHERE子句中的列上添加索引。那些肯定会有所帮助。
答案 1 :(得分:0)
除了对两个上的items_filters进行确认和索引(filter_id,value_id)之外,我还会预先通过分组对您的项目ID进行资格预审,然后加入项目表。看起来您正在尝试找到满足两个特定条件的项目,对于那些,请抓住项目......
我还在外部留下了“with by with rollup”,即使内部查询返回的每个ID都有一个实例。但由于内部查询已经应用了0,10条记录的限制,因此不会将过多的结果加入到您的项目表中。
但是,由于您没有进行任何聚合,我相信外部的group by和rollup并不会真正为您提供任何好处,否则可能会被删除。
SELECT i.*
FROM
( select itf.item_id
from items_filters itf
WHERE (itf.filter_id = 1 AND itf.value_id = '1')
OR (itf.filter_id = 2 AND itf.value_id = '7')
GROUP BY itf.item_id
HAVING COUNT(*) = 2
LIMIT 0, 10 ) PreQualified
JOIN items i
ON PreQualified.item_id = i.item_id
另一种方法可能是在内部查询上进行JOIN,因此您甚至不需要应用组和拥有。由于您明确要查找两个项目,我会尝试以下内容。这样,第一个限定符就是它必须有一个ID = 1和value ='1'的条目。它甚至没有打入这个条目,它永远不会关注第二个。然后,通过将连接应用于同一个表(别名itf2),它必须在相同的ID上找到 - 和第二个的条件(id = 2 value ='7')。这基本上强制看起来几乎像单个传递对一个条目FIRST,最重要的是在考虑其他任何事情之前。在收到项目详细信息之前,这仍然会导致您的有限10套。
SELECT i.*
FROM
( select itf.item_id
from items_filters itf
join items_filters itf2
on itf.item_id = itf2.item_id
AND itf2.filter_id = 2
AND itf2.value_id = '7'
WHERE
itf.filter_id = 1 AND itf.value_id = '1'
LIMIT 0, 10 ) PreQualified
JOIN items i
ON PreQualified.item_id = i.item_id
我还根据你的重复评论(按照我的预期)通过/用汇总删除了这个组。