2013-04-26 58 views
0

我试图优化以下查询。我在考虑一个外连接可以做到这一点,但我无法将自己的想法包装在一起。MySQL的子查询优化 - 在不(子查询)

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

这工作得很好,但显著较慢得到更多的文章在用户浏览。任何想法或建议,将不胜感激。

回答

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)。

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) 

希望这有助于

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 
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表​​3210

article_attributes(article_id, article_attribute_id)

希望这有助于创造必要指标。