




用 GROUP BY + ORDER BY 可实现无需机器学习库的协同过滤推荐,核心是找相似用户并推荐其高频购买而目标用户未购的商品;需建联合索引、改 NOT IN 为 LEFT JOIN、分步处理稀疏行为,并为冷启动设计热门/新品兜底策略。
不需要机器学习库,MySQL 本身就能跑出“买了这个的人也买了那些”的基础推荐。核心思路是:找出和目标用户行为相似的其他用户,再取他们买过但目标用户没买过的商品。
假设表结构为 orders(user_id, product_id, created_at),想给用户 123 推荐:
product_id
SELECT product_id, COUNT(*) AS cnt
FROM orders
WHERE user_id IN (
SELECT DISTINCT user_id
FROM orders
WHERE product_id IN (
SELECT product_id FROM orders WHERE user_id = 123
) AND user_id != 123
)
AND product_id NOT IN (
SELECT product_id FROM orders WHERE user_id = 123
)
GROUP BY product_id
ORDER BY cnt DESC
LIMIT 5;
上面 SQL 在数据量稍大(比如相似用户超 5000 个)时会变慢,因为子查询嵌套+NOT IN容易触发全表扫描。真实项目中必须加索引,且改写为 LEFT JOIN 避免 NOT IN 对 NULL 敏感的问题。
ALTER TABLE orders ADD INDEX idx_uid_pid (user_id, product_id);
NOT IN 换成 LEFT JOIN ... IS NULL,更稳定
新用户没任何购买记录,上面逻辑直接返回空。不能卡住,得有兜底策略:
SELECT product_id FROM orders GROUP BY product_id ORDER BY COUNT(*) DESC LIMIT 5
products(created_at) 表)UNION ALL 后加 LIMIT 控制总数注意别在主查询里实时算热度权重,应预计算到缓存表或加字段(如 products.hot_score),否则每次推荐都扫全表。
有人尝试写三层 JOIN 模拟用户-商品-用户关系链,结果查几秒不出结果甚至 OOM。MySQL 的 JOIN 优化器对多层自连接非常不友好,尤其当 orders 表超百万行时,中间结果集极易膨胀。
LIMIT(比如先取 top 100 相似用户)可大幅提速,牺牲一点精度换响应时间EXPLAIN FORMAT=TREE 看是否走了索引,以及 rows 估算是否合理推荐逻辑越简单,越要盯死执行计划和实际耗时——看起来一行 SQL 很轻量,背后可能扫千万行。