MySQL语句提速优化:快速筛选用户未评分的新影片行
我之前也碰到过类似的用户未评分内容筛选慢的情况,结合你给出的表结构和当前问题,分享几个实测有效的优化思路:
1. 给rating表添加覆盖型复合索引
你的核心过滤逻辑之一是「找出用户1已评分的所有影片ID」,当前如果rating表没有合适的索引,MySQL会做全表扫描来匹配userid=1的记录。
直接创建这个复合索引:
CREATE INDEX idx_rating_userid_netflixid ON rating(userid, netflixid);
这个索引是覆盖索引——查询SELECT netflixid FROM rating WHERE userid=1时,MySQL不需要回表查询rating的其他字段,直接从索引里就能拿到需要的netflixid,速度会提升非常明显。
2. 给films表的过滤字段加索引
既然你已经把countrylist拆成了独立的tinyint列(假设列名叫is_uk,值为1代表英国),给这个列加上索引,同时结合netflixid做复合索引会更高效:
CREATE INDEX idx_films_country_netflixid ON films(is_uk, netflixid);
这个索引能让MySQL快速筛选出符合国家条件的影片,同时netflixid在索引中,后续和rating表关联时不需要再去查主表数据。
3. 改用LEFT JOIN + IS NULL的写法替代NOT IN/NOT EXISTS
虽然理论上NOT EXISTS和LEFT JOIN的执行计划应该相近,但实际场景中,配合合适的索引,LEFT JOIN的表现有时会更稳定。试试这个SQL:
SELECT f.* FROM films f LEFT JOIN rating r ON f.netflixid = r.netflixid AND r.userid = 1 WHERE f.is_uk = 1 AND r.netflixid IS NULL LIMIT 1;
这个逻辑是:先找出所有英国影片,再左关联用户1的评分记录,没有匹配到评分(r.netflixid IS NULL)的就是未评分的影片,LIMIT 1直接取第一条。
4. 用EXPLAIN分析执行计划
不管用哪种写法,一定要用EXPLAIN查看执行计划,确认索引是否生效:
EXPLAIN SELECT * FROM films WHERE ... -- 你的原查询或新查询
重点看type列:如果是ALL说明是全表扫描,要调整索引;如果是ref/range/eq_ref说明用到了索引,是正常的。另外看Extra列,如果出现Using index说明用到了覆盖索引,这就是我们想要的效果。
内容的提问来源于stack exchange,提问作者Peter Turner

