Mysql查询:内部连接时文件排序、限制和排序依据
我正在尝试优化此查询:Mysql查询:内部连接时文件排序、限制和排序依据,mysql,Mysql,我正在尝试优化此查询: SELECT articles.id FROM articles INNER JOIN articles_authors ON articles.id=articles_authors.fk_Articles WHERE articles_authors.fk_Authors=586 ORDER BY articles.publicationDate LIMIT 0,50; 表格文章: id (1), select_type(SIMPLE), TABLE(art
SELECT articles.id
FROM articles
INNER JOIN articles_authors ON articles.id=articles_authors.fk_Articles
WHERE articles_authors.fk_Authors=586
ORDER BY articles.publicationDate LIMIT 0,50;
表格文章:
id (1), select_type(SIMPLE), TABLE(articles_authors), TYPE(ref), possible_keys(fk_Articles_fk_Authors, fk_Articles, fk_Authors), KEY (fk_Authors), Key_len(4), ref(const), ROWS(171568), extra (USING TEMPORARY; USING FILE sort)
id (1), select_type(SIMPLE), TABLE(articles), TYPE(eq_ref), possible_keys(PRIMARY), KEY (PRIMARY), Key_len(4), ref(articles_authors.fk_Authors), ROWS(1), extra ()
- 引擎:MyISAM
- 行格式:动态
- 行数:1482588
- 数据长度:78892672
- 最大数据长度:281474976710655
- 索引长度:127300608
- 无数据:0
- 校验和:空
谢谢你的帮助 它是使用索引,就像解释中所说的那样
id (1), select_type(SIMPLE), TABLE(articles_authors), TYPE(ref),
possible_keys(fk_Articles_fk_Authors, fk_Articles, fk_Authors),`
`KEY (fk_Authors), Key_len(4)`, ref(const), ROWS(171568),
extra (USING TEMPORARY; USING FILE sort)
只有在选择了50行并按发布日期排序后,才执行文件排序。它创建了一个包含50项的临时表。然后使用tablesort进行排序。
这个必须这样做,因为MySQL不能在那些孤立的50个项目上使用大索引,这将花费大量IO访问时间 对内存中的50个数字进行排序比访问磁盘上的索引更快 您可以通过以下方式加快查询速度:
optimize table articles, articles_authors
然后重新运行查询
编辑:通过非规范化表格文章加快建议速度
如果按照以下方式重写查询:
SELECT articles.id FROM articles WHERE articles.id IN (
SELECT articles_authors.fk_articles WHERE articles_authors.fk_authors = 586
LIMIT 0,50
)
ORDER BY articles.publicationDate;
您可能会看到相同的性能,但它突出了问题所在。
如果author 586有180000篇文章,那么MySQL必须在articles_authors中搜索180k中的50项,然后在order表中再次搜索180k中的50项
如果合并表文章作者和文章,表文章将被非规范化(假设一篇文章可以有多个作者),但您不必进行连接,您可以保存第二次搜索
CREATE TABLE `articles` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`publicationDate` date NOT NULL DEFAULT '1970-01-01',
`title` varchar(255) NOT NULL,
`fk_Authors` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `Articles_fk_Authors` (`id`,`fk_Authors`),
KEY `fk_Authors` (`fk_Authors`),
KEY `publicationDate` (`publicationDate`)
) ENGINE=MyISAM AUTO_INCREMENT=2349047 DEFAULT CHARSET=utf8
现在你可以像这样从中选择
SELECT articles.id FROM articles WHERE articles.Author = 586
ORDER BY articles.publicationDate LIMIT 50,0
也许这会帮助你:
SELECT articles.id
FROM articles
INNER JOIN (SELECT fk_Articles FROM articles_authors WHERE articles_authors.fk_Authors=586) sub ON articles.id=sub.fk_Articles
ORDER BY articles.publicationDate LIMIT 0,50;
不确定,但康拉德的建议似乎改变了排序和限制,因此您可能会以排序顺序获得随机列表的前50项,而不是排序列表的前50项 如果视图由fk_作者publicationDate订购,并且有索引,是否可以使用join帮助进行查看?还取决于您正在优化什么,速度还是磁盘空间 你能在Mysql中使用吗?它可能会更好吗?(示例代码,未选中)
这实际上可能是有效的,这取决于您的数据
SELECT articles.id
FROM articles
INNER JOIN articles_authors ON articles.id=articles_authors.fk_Articles
WHERE articles_authors.fk_Authors=586
ORDER BY articles.publicationDate LIMIT 0,50;
如果articles_authors.fk_authors=586根据数据库引擎收集的统计数据得出相当罕见的行,那么获取全部行和前50行的成本会更低
相比之下,如果它导致了大多数文章,那么查阅articles.publicationDate的索引并过滤掉无效行会更便宜,直到您获得所需的50行。+1,这是一个记录完整的问题!喜欢当人们真的包含相关信息时!我看不出如何对其进行更多优化,因为在where/order子句中,您有来自两个不同表的值,并且无法创建复合索引
(fk_Authors,publicationDate)
编辑答案以包含反规范化选项。感谢您的回复。我执行“优化表格文章、文章和作者”。但性能问题仍然存在。有一位作家有18万篇文章。查询耗时超过30秒,并注意到大IO访问。选择文本并按{}
按钮将为您格式化SQL代码。我想每行开头的四个空格就可以了same@Conrad:这就是{}
所做的一切。。。在所选文本块的每行开始处放置4个字符。
SELECT articles.id
FROM articles
INNER JOIN articles_authors ON articles.id=articles_authors.fk_Articles
WHERE articles.id=586
ORDER BY articles.publicationDate LIMIT 0,50;
SELECT articles.id
FROM articles
INNER JOIN (SELECT fk_Articles FROM articles_authors WHERE articles_authors.fk_Authors=586) sub ON articles.id=sub.fk_Articles
ORDER BY articles.publicationDate LIMIT 0,50;
SELECT id FROM articles WHERE id IN
(SELECT fk_Articles FROM articles_authors WHERE fk_Authors=586) as IDs
ORDER BY publicationDate LIMIT 0,50;
SELECT articles.id
FROM articles
INNER JOIN articles_authors ON articles.id=articles_authors.fk_Articles
WHERE articles_authors.fk_Authors=586
ORDER BY articles.publicationDate LIMIT 0,50;