所以基本上我有两个表,包含URL和TAGS,两者之间通过连接表TAGS_URLS具有has-and-belongs-to-many关系。
按标签查找网址的简单查询是:
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”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级别?
答案 0 :(得分: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可以很好地处理几个内连接,但随着交叉点数量的增加,性能会降低。答案 1 :(得分:0)
您可以尝试使用连接替换第二个statmenet中的sql子查询。 Robert Vieira在他的Sql Server书中声称,有时连接速度更快,有时子查询速度更快。很难相信MySql也不会这样。此外,如果表中有相当多的其他数据,除了'list'或'sample',那么您可能希望将此数据插入临时表并从该表运行查询。如果您要对该数据运行多个查询,则尤其如此。