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

Posted

技术标签:

【中文标题】在此查询上使用 RIGHT JOIN 时 JOIN 非常慢【英文标题】:JOIN very slow when using RIGHT JOIN on this query 【发布时间】:2012-04-05 00:18:44 【问题描述】:

我遇到了这个需要几秒钟才能完成的查询的问题。我已经尝试了很多优化,但我现在正在拍摄空白。

表格如下(并没有完全标准化,尤其是轨道表)

CREATE TABLE `tracks` (
`id` int(14) unsigned NOT NULL AUTO_INCREMENT,
`artist` varchar(200) NOT NULL,
`track` varchar(200) NOT NULL,
`album` varchar(200) NOT NULL,
`path` text NOT NULL,
`tags` text NOT NULL,
`priority` int(10) NOT NULL DEFAULT '0',
`lastplayed` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`lastrequested` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
`usable` int(1) NOT NULL DEFAULT '0',
`accepter` varchar(200) NOT NULL DEFAULT '',
`lasteditor` varchar(200) NOT NULL DEFAULT '',
`hash` varchar(40) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `hash` (`hash`),
FULLTEXT KEY `searchindex` (`tags`,`artist`,`track`,`album`),
FULLTEXT KEY `artist` (`artist`,`track`,`album`,`tags`)
) ENGINE=MyISAM AUTO_INCREMENT=3336 DEFAULT CHARSET=utf8

CREATE TABLE `esong` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`hash` varchar(40) COLLATE utf8_bin NOT NULL,
`len` int(10) unsigned NOT NULL,
`meta` text COLLATE utf8_bin NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `hash` (`hash`)
) ENGINE=InnoDB AUTO_INCREMENT=16032 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

CREATE TABLE `efave` (
`id` int(10) unsigned NOT NULL DEFAULT '0',
`inick` int(10) unsigned NOT NULL,
`isong` int(10) unsigned NOT NULL,
UNIQUE KEY `inick` (`inick`,`isong`),
KEY `isong` (`isong`),
CONSTRAINT `inick` FOREIGN KEY (`inick`) REFERENCES `enick` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT `isong` FOREIGN KEY (`isong`) REFERENCES `esong` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8

CREATE TABLE `enick` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT
`nick` varchar(30) COLLATE utf8_bin NOT NULL,
`dta` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`dtb` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`id`),
KEY `nick` (`nick`)
) ENGINE=InnoDB AUTO_INCREMENT=488 DEFAULT CHARSET=utf8 COLLATE=utf8_bin

我尝试以正常速度执行的查询如下

SELECT esong.meta, tracks.id FROM tracks RIGHT JOIN esong ON tracks.hash = esong.hash JOIN efave ON efave.isong = esong.id JOIN enick ON efave.inick = enick.id WHERE enick.nick = lower('nickname');

如果您删除 RIGHT JOIN 并将其更改为 JOIN 它会很快

EXPLAIN 给了我这个结果,似乎在 efave 选择中有一个小问题,但我不知道如何解决这个问题

+----+-------------+--------+--------+---------------+---------+---------+-----------------------+------+----------+--------------------------+
| id | select_type | table  | type   | possible_keys | key     | key_len | ref                   | rows | filtered | Extra                    |
+----+-------------+--------+--------+---------------+---------+---------+-----------------------+------+----------+--------------------------+
|  1 | SIMPLE      | enick  | ref    | PRIMARY,nick  | nick    | 92      | const                 |    1 |   100.00 | Using where; Using index |
|  1 | SIMPLE      | efave  | ref    | inick,isong   | inick   | 4       | radiosite.enick.id    |   12 |   100.00 | Using index              |
|  1 | SIMPLE      | esong  | eq_ref | PRIMARY       | PRIMARY | 4       | radiosite.efave.isong |    1 |   100.00 |                          |
|  1 | SIMPLE      | tracks | ALL    | hash          | NULL    | NULL    | NULL                  | 3210 |   100.00 |                          |
+----+-------------+--------+--------+---------------+---------+---------+-----------------------+------+----------+--------------------------+

【问题讨论】:

COLLATE 表的tracks 值是多少? 【参考方案1】:

你的解释看起来很干净,唯一让我印象深刻的是 esong 表使用 utf8_bin 的排序规则,并且 track 表没有指定排序规则,这表示它可能正在使用 another 排序规则类型。尝试对齐排序规则并查看连接的执行情况。

【讨论】:

这确实是问题所在,轨道表上的排序规则是 utf8_general_ci 而其他三个是 utf8_bin。绝对精彩。 啊,很高兴它成功了。我假设您将 utf8_bin collat​​e 添加到轨道表中? 我最初将 utf8_bin 添加到曲目中,但这使得全文索引区分大小写。所以我把它们都改成了 utf8_general_ci。【参考方案2】:

您检查过您的执行计划吗?如果没有,请运行您的查询以包含它。您的 Right Join 可能正在执行 Index Scan 而不是 Index Seek。或者您可能缺少索引。无论哪种方式,您都需要查看执行计划,以便更好地优化查询。在您知道真正的问题是什么之前,没有人能够真正告诉您如何使用 Right Join(或就此而言的 Join)使其更快。这里有一些链接.. 对于 mysql:http://dev.mysql.com/doc/refman/5.5/en/execution-plan-information.html 对于 SqlServer:http://www.sql-server-performance.com/2006/query-execution-plan-analysis/

【讨论】:

问题中有执行计划-最后的解释输出。 对不起,我没有意识到那是执行计划的结果。我什至没有检查 - 我认为这是您查询本身的结果。让我检查一下。

以上是关于在此查询上使用 RIGHT JOIN 时 JOIN 非常慢的主要内容,如果未能解决你的问题,请参考以下文章

mysql的unionleft join right join inner join和视图学习

Oracle left join 或right join

left join,right join,inner join,full join之间的区别

inner join(内连接)left join(左连接)right join(右连接)full join(全连接)区别

sql inner join 与 left join和right join 执行效率上面有多大差别?

mysql的inner join,left jion,right join,cross join以及on和where的区别