我有以下疑问。
SELECT * FROM video LEFT OUTER JOIN comments ON (video.id = comments.video_id)
WHERE comments.posted_by_user = 1234 OR video.id in (1, 2, 3, 4)
我有
video.id
comments.posted_by_user
和 comments.video_id
的索引。然而,mysql 对视频表进行全表扫描,这需要花费大量时间。使用 UNION
代替 LEFT OUTER JOIN
会更快,但不是一个选项,因为查询是由 django ORM 生成的。
为什么
OR
子句和 LEFT OUTER JOIN
的组合会阻止 mysql 使用索引?如何阻止它?
这并不是两者的结合导致速度变慢 - 您所要求的只能通过视频表的全表扫描来实现。无论评论表中是否有匹配的行,您都要求视频表中的所有行。
您可以通过将查询拆分为两个查询并将它们联合在一起来避免 OR 引起的 SQL 缓慢部分问题:
SELECT *
FROM video
LEFT JOIN comments ON (video.id = comments.video_id)
WHERE video.id IN (1, 2, 3, 4)
UNION
SELECT *
FROM video
LEFT JOIN comments ON (video.id = comments.video_id)
WHERE comments.posted_by_user = 1234;
第一部分执行起来会很快,因为您只从视频表中获取 video.id IN (1,2,3,4) 的行,并且大概 video.id 已建立索引。
第二部分可以利用评论索引(posted_by_user,video_id)索引(如果你有它 - 如果你没有添加它)通过首先查看评论表来优化执行。
披露:我写了引用的文章。