2011-04-22 35 views
10

我试图优化这个查询的限制和秩序: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; 

表的文章:

  • 引擎:MyISAM数据
  • ROW_FORMAT :动态
  • 行数:1 482 588
  • 数据长度:788 926 672
  • 最大数据长度:281 474 976 710 655
  • 索引长度:127 300 608
  • 数据免费:0
  • 校验:空
 CREATE TABLE `articles` (
     `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT, 
    `title` VARCHAR(255) NOT NULL, 
    `publicationDate` DATE NOT NULL DEFAULT '1970-01-01', 
    PRIMARY KEY (`id`), 
    KEY `publicationDate` (`publicationDate`) 
    ) ENGINE=MYISAM AUTO_INCREMENT=1498496 DEFAULT CHARSET=utf8

表articles_authors:

  • 引擎:MyISAM
  • ROW_FORMAT:动态
  • 行数:1 970 750
  • DATA_LENGTH:45 008 420
  • 最大数据长度:281 474 976 710 655
  • 索引长度:127 300 608
  • 数据免费:0
  • 校验:空
 CREATE TABLE `articles_authors` (
    `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 
    `fk_Articles` int(10) unsigned NOT NULL, 
    `fk_Authors` int(10) unsigned NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `fk_Articles_fk_Authors` (`fk_Articles`,`fk_Authors`), 
    KEY `fk_Articles` (`fk_Articles`), 
    KEY `fk_Authors` (`fk_Authors`), 
    ) ENGINE=MyISAM AUTO_INCREMENT=2349047 DEFAULT CHARSET=utf8

解释上查询:

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() 

正如你所看到的,SQL查询不优化(使用文件排序中讲解)。

感谢您的帮助!

+1

+1,对于一个有据可查的问题!当人们真正包含相关信息时就喜欢它! – 2011-04-22 17:59:09

+0

我不明白这可以如何优化更多,因为在where/order子句中,您具有来自两个不同表格的值,并且您无法创建组合索引'(fk_Authors,publicationDate)' – Pentium10 2011-04-22 21:30:22

+0

编辑答案包括去标准化选项。 – Johan 2011-04-26 12:31:13

回答

1

使用索引,就像它在解释中说的那样。

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个项目的临时表。然后它与桌面排序。
这个这样做,因为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; 

你可能会看到相同的性能,而它突出的问题。 如果作者586有180,000篇文章,那么MySQL必须从articles_authors中的180k中搜索50项,然后在订单表中再次从180k中搜索50项。

如果您合并表article_authors和文章,您的表文章将非规范化(假设文章可以有多个作者)但您不必进行连接,并且您自己保存第二个搜索。

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 
+0

感谢您的回复。 我执行“优化表文章articles_authors”。但性能问题仍然出现。 有一位作者有180 000篇文章。查询需要超过30秒,并且会注意到大IO访问。 – heisenberg 2011-04-26 08:22:53

0
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; 
+0

选择文本并按下“{}”按钮将为您设置SQL代码的格式。我认为每行开头的四个空格将会执行相同的操作 – 2011-05-03 20:38:59

+0

@Conrad:这就是所有的'{}'所做的......将4个字符放在选定文本块中每行的开头。 – 2011-05-05 18:33:49

1

也许这将帮助你:

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; 
0

不知道,但康拉德的建议似乎改变排序和限制,因此您可能会按排序顺序获得随机列表的前50项,而不是排序列表的前50项。

如果按照fk_author,publicationDate和索引排序,可以使用联接帮助来查看视图吗?还取决于你正在优化,速度或磁盘空间?

你可以在Mysql中使用IN吗?它可能会更好地优化吗? (示例代码,未选中)

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; 
0

这实际上可能是有效的,这取决于您的数据。

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行。