在限制行大小和表成员资格的同时加速内部联接和子查询

时间:2010-03-13 23:31:55

标签: sql mysql database subquery join

我正在开发一个使用贝叶斯过滤器的rss提要阅读器来过滤枯燥的博客帖子。

Stream表用作FIFO缓冲区,webapp将从中使用“条目”。我用它来存储条目,用户和贝叶斯过滤器分类之间的临时关系。

用户将条目标记为已读取后,将其添加到元数据表中(以便不向用户显示已读取的内容),并从流表中删除。每隔三分钟,后台进程将使用新条目重新填充Stream表(即,在检查rss提要更新后守护进程添加新条目时)。

问题:我提出的查询是hella slow。更重要的是,Stream表一次只需要保存一百个未读条目;它可以减少重复,加快处理速度,并为我显示条目提供一些灵活性。

查询(3600个没有索引的项目大约需要9秒):

insert into stream (entry_id, user_id) 
select entries.id, subscriptions_users.user_id 
 from entries 
inner join subscriptions_users on subscriptions_users.subscription_id = entries.subscription_id 
where subscriptions_users.user_id = 1 
  and entries.id not in (select entry_id 
                           from metadata 
                          where metadata.user_id = 1) 
  and entries.id not in (select entry_id 
                          from stream where user_id = 1);

查询说明:将用户尚未阅读的用户订阅列表(subscriptions_users)中的所有条目插入流中(即元数据中不存在),以及流中尚不存在的条目。

尝试的解决方案:在最后添加限制100会大大加快查询速度,但是一旦重复执行,将继续添加一组不同的100个条目,这些条目在表中不存在(每个成功的查询需要更长时间) 。

这很接近但不完全是我想做的事。

有没有人有任何建议(nosql?)或者知道更有效的撰写查询的方式?

3 个答案:

答案 0 :(得分:1)

  

查询(大约需要9秒钟   3600项没有索引的项目):

然后我会尝试从一些索引开始......

OR LEFT JOIN NULL (和索引)

SELECT *
FROM TABLEA A LEFT JOIN
    TABLEB B ON A.ID = B. ID
WHERE B.ID IS NULL

答案 1 :(得分:1)

使用:

INSERT INTO STREAM 
  (entry_id, user_id) 
   SELECT e.id, 
          su.user_id 
     FROM ENTRIES e
     JOIN SUBSCRIPTIONS_USERS su ON su.subscription_id = e.subscription_id 
                                AND su.user_id = 1 
LEFT JOIN METADATA md ON md.entry_id = e.id
                     AND md.user_id = 1
LEFT JOIN STREAM s ON s.entry_id = e.id
                  AND s.user_id = 1
    WHERE md.entry_id IS NULL
      AND s.entry_id IS NULL

在MySQL中,LEFT JOIN/IS NULL是获取一个表中存在的数据的最有效方法,而不是另一个表中存在的数据。 Reference link

在查看索引之前检查查询性能。

在Postgres中:

  • NOT IN
  • NOT EXISTS
  • LEFT JOIN / IS NULL

... are equivalent

答案 2 :(得分:0)

优化选择的一种方法是用连接替换子查询。

类似的东西:

select entries.id, subscriptions_users.user_id
from entries 
inner join subscriptions_users on subscriptions_users.subscription_id = entries.subscription_id 
left join metadata  md on (user_id,entry_id)
left join stream  str on (user_id, entry_id) 
where subscriptions_users.user_id = 1 and where md.user_id is null and str.user_id is null;

您必须确保左连接的连接条件正确。我不确定你的确切架构是什么,所以我不能。

此外,添加索引也会有所帮助。