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
  • 校验和:空
如您所见,SQL查询没有优化(在explain中使用文件排序)


谢谢你的帮助

是使用索引,就像解释中所说的那样

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;