Mysql查询:文件排序时内连接,限制和排序依据

hei*_*erg 12 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;
Run Code Online (Sandbox Code Playgroud)

表文章:

  • 引擎:MyISAM
  • Row_format:动态
  • 行:1 482 588
  • Data_length:788 926 672
  • 最大数据长度:281 474 976 710 655
  • 索引长度:127 300 608
  • 数据免费:0
  • 校验和:null
    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
  • 校验和:null
    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 ()
Run Code Online (Sandbox Code Playgroud)

如您所见,SQL查询未进行优化(在解释中使用文件排序).

谢谢你的帮助!

Joh*_*ica 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)
Run Code Online (Sandbox Code Playgroud)

仅作为其选择的 50 行以及按发布日期排序的额外内容,它才会进行文件排序。
它创建一个包含 50 个项目的临时表。然后用 tablesort 对其进行排序。必须
这样做,因为MySQL不能对那些孤独的50个项目使用大索引,这会花费大量的IO访问时间。

对内存中的 50 个数字进行排序比访问磁盘上的索引更快。

不过,您可以采取一些措施来加快查询速度:

optimize table articles, articles_authors
Run Code Online (Sandbox Code Playgroud)

并重新运行查询。

编辑:通过非规范化表格文章来加快建议速度

如果您像这样重写查询:

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;
Run Code Online (Sandbox Code Playgroud)

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

如果您合并表article_authors和articles,您的表文章将被非规范化(假设一篇文章可以有多个作者),但您不必进行连接,并且可以节省第二次搜索。

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 
Run Code Online (Sandbox Code Playgroud)

现在你可以像这样从中选择

SELECT articles.id FROM articles WHERE articles.Author = 586 
ORDER BY articles.publicationDate LIMIT 50,0
Run Code Online (Sandbox Code Playgroud)