Ste*_* C. 5 mysql has-and-belongs-to-many intersect
所以基本上我有两个表,包含URL和TAGS,通过连接表TAGS_URLS在两者之间具有has-and-belongs-to-many关系.
通过标记查找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");
Run Code Online (Sandbox Code Playgroud)
但是,我正在尝试恢复包含所有一组标记的所有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;
Run Code Online (Sandbox Code Playgroud)
结果集是正确的,但性能可怕.
我目前还在Redis数据库中将数据复制为存储在标记集中的URL ID列表,这样我就可以做到这样的事情并很快得到结果集.
SINTER "tag-sample" "tag-list"
Run Code Online (Sandbox Code Playgroud)
通过合理的努力,是否有可能通过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'
Run Code Online (Sandbox Code Playgroud)
您将继续向 tag_urls 添加成对的内部联接,并为您想要与之相交的每个“标签”添加标签。再次,通过解释来运行它并确保所有内容都有正确的索引。
DBMS 可以很好地处理多个内部联接,但随着交集数量的增加,性能将会下降。
归档时间: |
|
查看次数: |
2135 次 |
最近记录: |