我有树桌。视频,类别和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
我得到的结果是包含一个视频与视频类别数相同的次数。还有一件事是视频表有55 300行,而数据透视表video_categories有40万行,所以我不能使用DISTINCT而不是查询运行大约10秒。
我从PHP调用此查询,并且由于分页而无法从检索中手动排除类别。
有任何建议我该怎么做?
修改 一个视频可以有很多类别。所以这是多方面的关系。
答案 0 :(得分:2)
你现在拥有它的查询不仅效率低下(除了我认为是错误的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
)的复合群集密钥。
答案 1 :(得分:1)
您有桌面视频和video_categories。 目前还不知道它们之间的关系。
如果video_categories是一对一的视频表,那么您的查询将不会返回重复记录。
所以,我假设同一个视频有多个video_categories。
在这种情况下,这是一个可行的解决方案:
select * from video
where video_id in
(select video_id from video_category
where category_id not in (list of meaninless ids))