我正在尝试优化以下查询。我认为外部联接可以解决这个问题,但是我无法理解如何将它组合在一起。
// ---------------------------------
// Simplified representation of data
// ---------------------------------
create table views (
user_id,
article_id
)
create table article_attributes (
article_id,
article_attribute_id
)
create table articles (
id,
title,
date
)
Views表有数千万条记录。 文章表有几十万。
我正在尝试将所有文章与某个与之关联的属性进行匹配,并且用户尚未查看过该文章。
我尝试了什么,但不能很好地扩展:
select a.title, a.sid as article_id, a.total_views as times_read, a.date
from articles a
join article_attributes att on att.article_id = a.sid
where a.sid not in(
select v.article_id
from views v
join article_attributes att on att.article_id = v.article_id
where user_id = 132385
and att.article_attribute_id = 10
group by v.article_id
)
and att.article_attribute_id = 10
and a.date >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 day)
order by total_views desc
limit 5
这种方法很好,但是用户查看的文章越多,速度就越慢。任何想法或建议将不胜感激。
答案 0 :(得分:1)
SELECT a.title, a.sid AS article_id, a.total_views AS times_read, a.date
FROM articles a
JOIN article_attributes att
ON a.id = att.article_id AND att.article_attribute_id = 10
LEFT JOIN views v
ON a.id = v.article_id AND v.user_id = 132385
WHERE v.user_id IS NULL
尽量避免嵌套查询,让引擎完成它的工作。请注意,您可以在其他过滤器(DATE,ORDER BY)上标记。
答案 1 :(得分:1)
尝试此查询
select a.title, a.sid as article_id, a.total_views as times_read, a.date
from
articles a
left join
views v
on
a.sid = v.article_id AND v.article_id is null
join
article_attributes att
on
att.article_id = v.article_id AND v.user_id = 132385 AND att.article_attribute_id = 10
where
a.date >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 day)
order by
total_views desc limit 5
为articles
表(total_views, sid, date)
view
表(article_id, user_id)
article_attributes
表(article_id, article_attribute_id)
希望这有帮助。
答案 2 :(得分:0)
我建议在连接中使用子查询,而不是将子查询用作where
条件。另外,我建议您不要在子查询中使用group by
,而是select distinct
:
select
a.title, a.sid as article_id, a.total_views as times_read, a.date
from
(articles a
inner join article_attributes att on a.sid = att.article_id)
left join (
select distinct
v.article_id
from views v
inner join article_attributes att on v.article_id = att.article_id
where
user_id = 132385
and att.article_atribute_id = 10
) as b on a.sid = b.article_id
where
b.article_id is null
and att.article_attribute_id = 10
and a.date >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 day)
希望这有帮助
答案 3 :(得分:0)
EXISTS
的效果应优于IN
:
SELECT a.title,
a.sid AS article_id,
a.total_views AS times_read,
a.date
FROM articles a
JOIN article_attributes att ON att.article_id = a.sid
WHERE NOT EXISTS (SELECT 0
FROM views v
JOIN article_attributes att ON att.article_id = v.article_id
WHERE user_id = 132385
AND att.article_attribute_id = 10
AND v.article_id = a.sid )
AND att.article_attribute_id = 10
AND a.date >= DATE_SUB(CURRENT_DATE(), INTERVAL 7 DAY)
ORDER BY total_views DESC LIMIT 5