0

我正在尝试优化以下查询。我认为外部连接可以解决问题,但我不知道如何将它放在一起。

// ---------------------------------
// 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

这工作正常,但用户查看的文章越多,速度就会明显变慢。任何想法或建议将不胜感激。

4

4 回答 4

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
  1. 第一次加入只会让您获得具有给定属性的文章。
  2. 第二个联接采用第一个联接的结果并返回具有 user_id 的行以及第一个结果中没有 user_id 的所有剩余行。(基本上所有具有属性 132385 且 user_id 为 10 或 NULL 的文章)
  3. 那么我们想要的只是 user_id 为 NULL 的结果

尽量避免嵌套查询,让引擎完成它的工作。请注意,您可以在最后标记您的其他过滤器(DATE、ORDER BY)。

于 2013-04-27T15:15:46.897 回答
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)

希望这可以帮助。

于 2013-04-29T13:01:16.657 回答
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
于 2013-04-26T22:37:31.243 回答
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)

希望这可以帮助

于 2013-04-26T22:29:28.210 回答