【问题标题】:Performance in SQL sentence containing ORDER BY, LIMIT and COUNT包含 ORDER BY、LIMIT 和 COUNT 的 SQL 语句中的性能
【发布时间】:2012-11-23 23:48:06
【问题描述】:

我已经在一个 SQL 语句中搜索了改进这种危险的函数组合的方法......

为了让您了解上下文,我有一个表格,其中包含有关文章的若干信息(article_id、作者、...),另一个表格包含 article_id 和一个 tag_id。由于一篇文章可以有多个标签,因此第二个表可能有 2 行具有相同的 article_id 和不同的 tag_id。

为了获得与我想要的(在本例中为 1354)有更多共同标签的 8 篇文章的列表,我编写了以下查询:

SELECT articles.article_id, articles.author, count(articles_tags.article_id) as times
FROM articles
INNER JOIN articles_tags ON (articles.article_id=articles_tags.article_id)
WHERE id_tag IN
    (SELECT article_id FROM articles_tags WHERE article_id=1354)
AND article_id <> 1354
GROUP BY article_id
ORDER BY times DESC
LIMIT 8

这非常慢...... 50 万篇文章需要 90 秒。

通过删除“order by times”这句话,它几乎立即生效,但如果我这样做,我将不会得到最相似的文章。

我能做什么?

谢谢!!

【问题讨论】:

  • WHERE id_tag IN (SELECT article_id FROM articles_tags WHERE article_id=1354) - 对吗?我的意思是.. id_tag IN (SELECT article_id .. 似乎您尝试通过选择article_ids 来查找id_tags。我可能错了。
  • 这是什么 SQL 供应商?

标签: sql tags count sql-order-by


【解决方案1】:

对子选择的查询总是会浪费时间...此外,由于查询似乎并不准确或丢失,我假设您的文章标签表有两列.. . 一个用于实际文章 ID,另一个用于与其关联的 tag_ID。

也就是说,我会预先查询文章 1354(您感兴趣的文章)的标签 ID。在相同的标签 ID 上再次将其用作文章标签的笛卡尔连接。从此,您将获取文章标签别名的第二个版本并获取它的文章 ID,然后是 MATCH 的计数(通过联接而不是左联接)。像以前一样在文章 ID 上应用分组依据,并且为了微笑,加入文章表以获取作者。

现在,请注意。一些 SQL 引擎要求您按所有非聚合字段进行分组,因此您可能必须将作者添加到组中(无论如何,每个文章 ID 始终相同),或者将其更改为 MAX(A.author)作为 Author 会给出相同的结果。

我会在 (tag_id, article_id) 上有一个索引,以便从您希望找到的共同“常见”标签中找到这些标签。你可以有一篇文章有​​ 10 个标签,而另一篇文章有​​ 10 个完全不同的标签,结果共有 0 个。这将阻止其他文章甚至出现在结果集中。

您仍然有时间浏览您所描述的 50 万篇文章,这可能是数百万个实际标签条目。

select 
      AT2.article_id,
      A.Author,
      count(*) as Times
   from
      ( select ATG.id_tag
           from articles_tags ATG
           where ATG.Article_ID = 1354
           order by ATG.id_tag ) CommonTags
         JOIN articles_tags AT2
            on CommonTags.ID_Tag = AT2.ID_Tag
            AND AT2.Article_ID <> 1354
            JOIN articles A
               on AT2.Article_ID = A.Article_ID
   group by
      AT2.article_id
   order by
      Times DESC
   limit 8

【讨论】:

  • 我觉得你的查询很有趣,但实际上只在几秒钟内改进了时间,用了超过 1 分钟的时间来获取结果。可能与索引有关?
  • 我会考虑的唯一 OTHER 元素是“相似”,对于给定的文章,您需要至少一个“其他”标签,并预查询那些在最小值,然后继续其余的比较。这样可以申请吗?对于给定的文章,可以使用多少个标签进行测试,以及可以使用多少个“标签”来标记一篇文章。您的标签是否具有某种重要的“权重”,可用于比较“相似”?
【解决方案2】:

似乎应该可以在没有任何子查询的情况下做到这一点,然后可能会产生更快的查询。

在这里,感兴趣的文章与其标签相连,然后进一步与具有这些标签的其他文章相连。然后统计每篇文章的标签数量并排序:

SELECT a2.article_id, a2.author, COUNT(t2.tag_id) AS times
FROM articles a1 
INNER JOIN articles_tags t1
ON t1.article_id = a1.article_id   -- find tags for staring article
INNER JOIN tags t2
ON t2.tag_id = t1.tag_id           -- find other instances of those tags
AND t2.articles_id <> t1.articles_id
INNER JOIN articles a2
ON a2.articles_id = t2.articles_id -- and the articles where they are used
WHERE a1.article_id = 1354
GROUP BY a2.article_id, a2.author  -- count common tags by articles
ORDER BY times DESC
LIMIT 8

如果您知道共同标签数量的下限(例如 3 个),则在 ORDER BY times DESC 之前插入 HAVING times &gt; 2 可以进一步提高速度。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-01-10
    • 2016-03-18
    • 1970-01-01
    • 2011-11-20
    • 2017-05-12
    • 1970-01-01
    相关资源
    最近更新 更多