我有树 table 。 videos、categories 和 video_categories(基本上是视频和类别之间的数据透视表)。
我正在尝试获取所有没有特定类别的视频。问题是我的结果不止一次包含相同的视频,而我只需要一次。
这是我得到的
SELECT videos.* FROM videos
JOIN video_categories ON videos.id = video_categories.video_id
WHERE category_id NOT IN (64452, 1031, 32595, 1015, 26484, 1019)
ORDER BY downloads
我得到的结果是包含一个视频的次数与视频类别数相同。还有一件事是视频表有 55300 行,数据透视表 video_categories 有 400000 行,所以我不能只使用 DISTINCT 因为查询运行了大约 10 秒。
我从 PHP 调用此查询,由于分页,无法从检索到的类别中手动排除类别。
有什么建议吗?
编辑 一个视频可以有多个类别。所以它是多对多关系。
最佳答案
你目前的查询不仅效率低下而且是错误的(除了我认为是错字的 missing from 子句),当你运行时考虑一个视频有类别 1 和 1031:
SELECT videos.* FROM Videos
JOIN video_categories ON videos.id = video_categories.video_id
WHERE category_id NOT IN (64452, 1031, 32595, 1015, 26484, 1019)
ORDER BY downloads;
此视频将被退回,因为类别 1 不在提供的类别列表中。您需要做的是找到所有具有这些类别的视频,然后排除这些视频。我通常会使用 NOT EXISTS
来执行此操作,因为我认为它更合乎逻辑:
SELECT v.*
FROM Videos AS v
WHERE NOT EXISTS
( SELECT 1
FROM video_categories AS vc
WHERE vc.video_id = v.id
AND vc.category_id IN (64452, 1031, 32595, 1015, 26484, 1019)
);
然而,MySQL optimises this kind of query better using LEFT JOIN/IS NULL
:
SELECT v.*
FROM Videos AS v
LEFT JOIN video_categories AS vc
ON vc.video_id = v.id
AND vc.category_id IN (64452, 1031, 32595, 1015, 26484, 1019)
WHERE vc.Video_ID IS NULL;
如果这仍然不快,那么您可能缺少逻辑索引。在您的 Videos
表中,ID
应该是聚类键,而在 video_categories
中,您应该有一个复合聚类键 (video_id
,category_id
)。
关于mysql - 从数据透视表中获取不重复的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23937997/