通过联接表的MySQL INTERSECT?

| 因此,从本质上讲,我有两个表,其中包含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 \” AND \“ tag \” AND \“ 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级别?     
已邀请:
我不确定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 \'添加成对的内部联接到tag_urls和tag。再次,通过explain运行,并确保所有内容都具有正确的索引。 DBMS可以很好地使用多个内部联接,但是随着交叉点数量的增加,性能会下降。     
您可以尝试使用连接替换第二个statmenet中的sql子查询。罗伯特·维埃拉(Robert Vieira)在他的Sql Server书籍中声称,有时联接速度更快,有时子查询速度更快。很难相信,同样的事实对于MySql也不会成立。另外,如果表中除了\'list \'或\'sample \'之外还有很多其他数据,那么您可能希望将此数据插入到临时表中并从该表中运行查询。如果您要对该数据运行多个查询,则尤其如此。     

要回复问题请先登录注册