item_tag_map
有两列item_id
和tag_id
,两者都有索引。
以下是数据样本:
item_id tag_id
1 1
1 3
4 7
1 5
3 1
3 8
6 8
10 4
现在我想获得具有标签1,2,3,5的项目ID,并按所有标签的总数对结果进行排序。
以下是结果示例:
item_id count(m.tag_id)
1 3
3 1
我试过的SQL是:
SELECT m.item_id,count(m.tag_id) from item_tag_map AS m
WHERE tag_id in(1,2,3,5)
GROUP BY m.item_id
ORDER BY count(m.tag_id)
LIMIT 10
此表中大约有1万行,查询速度非常慢。我试图删除所有count
语句,然后它变得非常快。
为什么count
会减慢此查询的速度?如何优化此查询以使其快速?
答案 0 :(得分:4)
这是因为ORDER BY COUNT(m.tag_id)
。
MySQL需要获取所有行(即进行全表扫描)以计算item_id
的每个值的计数。
在这种情况下,MySQL无法使用索引。 (正如您在查看EXPLAIN SELECT ..
时所看到的那样)
从COUNT()
子句中删除ORDER BY
时,MySQL可以使用索引进行排序。
一种可能的解决方案是创建materialized view,其中DBMS在单独的表中缓存tag_id
每item_id
个值的计数。
MySQL本身不支持实体化视图,但您可以模拟它们:
您最初可以使用相关查询(INSERT INTO tag_counts SELECT ...
)创建表格,然后使用{{1触发器
或者,有一个名为FlexViews的第三方软件可以自动执行此过程。
这就是我如何保持每周数百万行的统计数据库的反应。