在 JOIN 值上完成时 MySQL 慢 ORDER BY?

Posted

技术标签:

【中文标题】在 JOIN 值上完成时 MySQL 慢 ORDER BY?【英文标题】:MySQL Slow ORDER BY when done on JOIN value? 【发布时间】:2016-06-06 00:49:12 【问题描述】:

我有这个问题:

SELECT
    c.*,
    cv.views
FROM 
    content AS c
JOIN
    content_views AS cv ON cv.content = c.record_num
WHERE 
    c.enabled = 1
ORDER BY
    cv.views

很简单,但是真的很慢...有没有办法让它更快?

这是我的解释:

id     select_type     table     type     possible_keys          key          key_len     ref          rows     Extra
1      SIMPLE          c         ref      enabled_2,enabled      enabled      4           const        23947    Using temporary; Using filesort
1      SIMPLE          cv        eq_ref   PRIMARY                PRIMARY      4           c.record_num 1    

编辑 2016-02-24

请注意,我通常使用 LIMIT,因此 EXPLAIN 中返回的记录数并不完全准确,但是为了简单起见,并且由于 LIMIT 或没有它,性能不会改变,我有删除它。

根据 cmets 的要求,这是我的 SHOW CREATE TABLE 的结果。如您所见,我的一个表是 MyISAM 而另一个是 InnoDB。

CREATE TABLE `content` (
 `title` varchar(255) NOT NULL DEFAULT '',
 `filename` varchar(255) NOT NULL DEFAULT '',
 `filename_2` varchar(255) NOT NULL,
 `filename_3` varchar(255) NOT NULL,
 `orig_filename` varchar(255) NOT NULL,
 `trailer_filename` varchar(255) NOT NULL,
 `thumbnail` varchar(255) NOT NULL DEFAULT '',
 `embed` text NOT NULL,
 `description` text NOT NULL,
 `paysite` int(11) NOT NULL DEFAULT '0',
 `keywords` varchar(255) NOT NULL,
 `model` varchar(255) NOT NULL DEFAULT '',
 `scheduled_date` date NOT NULL DEFAULT '0000-00-00',
 `date_added` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
 `encoded_date` datetime NOT NULL,
 `rating` int(5) NOT NULL DEFAULT '0',
 `length` int(11) NOT NULL DEFAULT '0',
 `submitter` int(11) NOT NULL DEFAULT '0',
 `ip` varchar(15) NOT NULL,
 `approved` int(11) NOT NULL DEFAULT '0',
 `hotlinked` varchar(1024) NOT NULL,
 `plug_url` varchar(255) NOT NULL,
 `enabled` int(11) NOT NULL DEFAULT '0',
 `main_thumb` int(11) NOT NULL DEFAULT '3',
 `xml` varchar(32) NOT NULL,
 `photos` int(11) NOT NULL DEFAULT '0',
 `mobile` varchar(255) NOT NULL,
 `modeltmp` varchar(255) NOT NULL,
 `movie_width` int(11) NOT NULL,
 `movie_height` int(11) NOT NULL,
 `token` varchar(255) DEFAULT NULL,
 `source_thumb_url` varchar(255) NOT NULL,
 `related` varchar(1024) NOT NULL,
 `force_related` varchar(255) NOT NULL,
 `record_num` int(11) NOT NULL AUTO_INCREMENT,
 `webvtt_src` text NOT NULL,
 `category_thumb` int(11) NOT NULL,
 `related_date` date NOT NULL,
 `publish_ready` tinyint(1) NOT NULL,
 PRIMARY KEY (`record_num`),
 KEY `encoded_date` (`encoded_date`,`photos`,`enabled`),
 KEY `filename` (`filename`),
 KEY `scheduled_date` (`scheduled_date`),
 KEY `enabled_2` (`enabled`,`length`,`photos`),
 KEY `enabled` (`enabled`,`encoded_date`,`photos`),
 KEY `rating` (`rating`,`enabled`,`photos`),
 KEY `token` (`token`),
 KEY `submitter` (`submitter`),
 FULLTEXT KEY `keywords` (`keywords`,`title`),
 FULLTEXT KEY `title` (`title`),
 FULLTEXT KEY `description` (`description`),
 FULLTEXT KEY `keywords_2` (`keywords`)
) ENGINE=MyISAM AUTO_INCREMENT=124207 DEFAULT CHARSET=latin1

CREATE TABLE `content_views` (
 `views` int(11) NOT NULL,
 `content` int(11) NOT NULL,
 PRIMARY KEY (`content`),
 KEY `views` (`views`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

【问题讨论】:

解释中没有什么可怕的,关于表格的信息? 请提供SHOW CREATE TABLE 您打算如何处理结果集中的 23,947 行?确定不把它们扔到网页上? 为了简单起见,我删除了 LIMIT,但无论有没有它,性能都是一样的。我已经在我的主帖中发布了 CREATE TABLE 【参考方案1】:

对于这个查询:

SELECT c.*, cv.views
FROM content c JOIN
     content_views cv
     ON cv.content = c.record_num
WHERE c.enabled = 1
ORDER BY cv.views;

最好的索引可能是content(enabled, record_num)content_views(content, views)。我猜即使有了这些索引,性能也会和你现在的差不多。

【讨论】:

(content, views) 如果是content=const ORDER BY views 会更好。他所拥有的没有views一个 的地方订购。然而,它有用的,因为它是“覆盖”的。也就是说,它不会阻止“文件排序”,但也不需要接触数据。另一方面,这可能是只有 2 列的 InnoDB。如果是这样,那么(content, views) 将与表冗余! (enabled, record_num) 也无济于事,因为它会想在c.* 存在时获取所有的信息。令人惊讶的是,他在“旗帜”上的索引甚至被使用了。 @RickJames。 . .复合索引是引擎在从数据页获取其余列之前使用该索引进行连接。 我认为 Handler 做了这一步。

以上是关于在 JOIN 值上完成时 MySQL 慢 ORDER BY?的主要内容,如果未能解决你的问题,请参考以下文章

在此查询上使用 RIGHT JOIN 时 JOIN 非常慢

MySQL Left Join 运行速度非常慢,拆分为 2 个查询要快得多

MySQL Left join 无法在单个查询中删除重复项

使用 ORDERBY 时的 MySQL 慢 JOIN 查询

在 MySQL 和 PHP 中使用多表和 LEFT JOIN 查询非常慢

即使使用 INNER JOIN 而不是 IN,MySQL 查询也非常慢