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 テーブルには数千万のレコードがあります。Articles テーブルには数十万の記事があります。

特定の属性が関連付けられていて、まだユーザーが閲覧していないすべての記事を照合しようとしています。

私が試したことはありますが、うまくスケーリングしません:

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 
 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 に答える
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. 2 番目の結合は、最初の結合の結果を取得し、user_id を持つ行と、user_id を持たない最初の結果の残りのすべての行を返します (基本的に、user_id が 10 または NULL の属性 132385 を持つすべての記事)。
  3. 次に必要なのは、user_id が NULL である結果だけです

ネストされたクエリを避け、エンジンに任せてください。最後に他のフィルター (DATE、ORDER BY) をタグ付けできることに注意してください。

于 2013-04-27T15:15:46.897 に答える
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 に答える