要将一个视频放在一个或多个类别中,我有以下表格:
Video (id, url, title, viewCount)
~1,000,000行VideoCategory (id, videoId, categoryId
~6,000,000行Category (id, name)
~200行
VideoCategory(categoryId, videoId)
上的索引Category(name)
上的唯一索引
以下查询在"汽车"类别中获取10个观看次数最多的视频的速度太慢(~5.5秒)。"汽车"类别包含200,000个视频。
SELECT v.* FROM Video v
JOIN VideoCategory vc ON vc.videoId = v.id
JOIN Category c ON vc.categoryId = c.id
WHERE c.name = 'Cars'
ORDER BY v.viewCount DESC
LIMIT 10
当查询一个只包含100个视频的类别时,需要大约0.05秒。EXPLAIN
"汽车"类别的查询。
+------+-------------+-------+--------+------------------------------------+--------------------+---------+-----------------------+--------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+--------+------------------------------------+--------------------+---------+-----------------------+--------+----------------------------------------------+
| 1 | SIMPLE | c | const | name_UNIQUE | name_UNIQUE | 322 | const | 1 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | vc | ref | fk_Category_idx,category_video_idx | category_video_idx | 8 | const | 493988 | Using index |
| 1 | SIMPLE | v | eq_ref | PRIMARY | PRIMARY | 8 | VideoDB.vc.videoId | 1 | Using where |
+------+-------------+-------+--------+------------------------------------+--------------------+---------+-----------------------+--------+----------------------------------------------+
我怎样才能加快速度(希望是0.1秒或更少)?忽略ORDER BY
有很大的影响,但它显然没有给我想要的结果。
- 更新**
我尝试了一下STRAIGHT_JOIN
,并观察到下面的查询有一些有趣的地方:
SELECT v.* FROM Video v
STRAIGHT_JOIN VideoCategory vc ON v.id = vc.videoId
WHERE vc.categoryId = (SELECT id FROM Category WHERE name = 'Cars')
ORDER BY v.viewCount ASC
LIMIT 10
它在0.011秒内返回!我还删除了JOIN Category c
并将其替换为WHERE vc.categoryId = (SELECT id FROM Category WHERE name = 'Cars')
,如果Category.name
不存在,则立即返回0个结果。
不幸的是,仅仅添加STRAIGHT_JOIN
并不能解决所有问题,它只对超过1000个视频的类别比较快,视频越多,它看起来就越快。对于少于100个视频的类别,它会变得非常慢,去掉STRAIGHT_JOIN
会让它再次变得非常快。
对于一个如此简单的查询,我期望计划者找到最优路径。这是怎么回事?
另一个观察结果是,将顺序从ASC
更改为DESC
将使某些类别的查询再次变慢,但对其他类别则不会变慢(例如,ASC将花费0.01秒,DESC将花费0.8秒)。
2条答案
按热度按时间rqmkfv5c1#
对于20万条记录来说,这种排序方式会花费很多时间。一个想法是创建一个定期更新的前10个表,这样你就可以只显示新的前10个表中的条目,这对用户来说会更快,数据库加载也更容易。
ngynwnxp2#
原始查询的最佳解决方案是在
Category.id
中查找“汽车”,这已经完成。然后,由于
VideoCategory
上缺少索引,查询计划福尔斯。我假设查找是从
categoryId
-〉videoId
开始的,那么应该有一个categoryId
索引。但是理想情况下,作为一个连接表,(categoryId, videoId)
可能是最合适的组合主键,可以改进您的查询。如果需要从videoId
-〉categoryId
进行反向解析,次索引键videoId
。主索引键已经包含在次索引键的结尾。viewCount
的最后一个问题是一个困难的问题,一些查询优化(如rowid_filter)可能会有所帮助。