5

所以本质上我有两个表,包含 URLS 和 TAGS,通过连接表 TAGS_URLS 在两者之间具有多属关系。

按标签查找 URL 的简单查询是:

SELECT urls.id FROM urls 
  INNER JOIN tags_urls ON urls.id=tags_urls.url_id
  INNER JOIN tags ON tags_urls.tag_id=tags.id 
WHERE tags.tag IN ("sample","tag","list");

但是,我正在尝试恢复包含所有一组标签的所有 URL 的交集。即,只有包含标签“sample”和“tag”和“list”的 URL。

我有一个有效的查询,但我无法在 30 秒内执行查询。

SELECT a.id
  FROM
    (SELECT DISTINCT urls.id FROM urls
      INNER JOIN tags_urls ON tags_urls.url_id=urls.id INNER JOIN tags ON tags.id=tags_urls.tag_id
      WHERE tags.tag = 'sample') a
  JOIN
     (SELECT DISTINCT urls.id FROM urls
      INNER JOIN tags_urls ON tags_urls.url_id=urls.id INNER JOIN tags ON tags.id=tags_urls.tag_id
      WHERE tags.tag = 'list') b
  ON a.id = b.id;

结果集是正确的,但性能是可怕的。

我目前也将数据复制到 Redis 数据库中,作为存储在标签集中的 URL id 列表,因此我可以执行类似的操作并非常快速地获得结果集。

SINTER "tag-sample" "tag-list"

通过合理的努力,是否有可能通过 SINTER 将该任务的 MySQL 性能提升到 Redis 的水平?

4

2 回答 2

1

我不是 100% 确定,但我认为底层引擎正在为您的每个子选择创建一个临时表。根据数据的大小,这可能会非常昂贵。如果它们很大(在您的情况下),则临时表必须将其内容写入磁盘,因为它们太大而无法立即保存在内存中。因此,基本上您的查询正在复制大量数据,因为它试图构建两个与您的两个子选择的选择条件相匹配的临时表。一旦完成,它最终会执行外部选择,这很可能相当快。

我会尝试将子选择排除在内部连接之外。我认为以下内容将为您提供所需的内容:

select urls.id from urls
inner join tags_urls tu1 on tu1.url_id = urls.id
inner join tags t1 on tu1.tag_id = t1.id and t1.tag = 'sample'
inner join tag_urls tu2 on tu2.url_id = urls.id
inner join tags t2 on t2.id = tu2.tag_id and t2.tag = 'list'

您将继续为您想要与之相交的每个“标签”添加成对的内部连接到 tag_urls 和标签。再次,通过解释运行它并确保所有内容都有正确的索引。

DBMS 可以很好地处理多个内部连接,但是随着交叉点数量的增加,性能会下降。

于 2011-04-15T23:05:23.307 回答
0

您可以尝试用连接替换第二个 statmenet 中的 sql 子查询。Robert Vieira 在他的 Sql Server 书籍中声称,有时连接更快,有时子查询更快。很难相信 MySql 也是如此。此外,如果表中有很多其他数据,而不是“列表”或“样本”,那么您可能希望将此数据插入临时表并从该表运行查询。如果您要对该数据运行多个查询,则尤其如此。

于 2011-04-15T22:49:33.483 回答