给出以下表格:
CREATE TABLE `webs_shoutbox` (
`shoutID` int(11) NOT NULL AUTO_INCREMENT,
`date` int(14) NOT NULL DEFAULT '0',
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`message` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
`ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '',
PRIMARY KEY (`shoutID`),
KEY `shoutID` (`shoutID`),
KEY `name` (`name`(191))
) ENGINE=InnoDB AUTO_INCREMENT=62982 DEFAULT CHARSET=utf8 COLLATE=utf8_roman_ci |
CREATE TABLE `webs_user` (
`userID` int(11) NOT NULL AUTO_INCREMENT,
`registerdate` int(14) NOT NULL DEFAULT '0',
`lastlogin` int(14) NOT NULL DEFAULT '0',
`username` varchar(255) COLLATE utf8_roman_ci NOT NULL DEFAULT '',
`password` varchar(255) COLLATE utf8_roman_ci NOT NULL DEFAULT '',
`nickname` varchar(255) COLLATE utf8_roman_ci NOT NULL DEFAULT '',
....,
....,
PRIMARY KEY (`userID`),
KEY `nickname` (`nickname`),
KEY `userID` (`userID`)
) ENGINE=MyISAM AUTO_INCREMENT=3366 DEFAULT CHARSET=utf8 COLLATE=utf8_roman_ci
webs_user
表包含大约4k条记录,webs_shoutbox
包含大约100万条记录。
我想使用left join
:
select shoutID, date, name, message, webs_user.userID
from webs_shoutbox
left join webs_user on webs_shoutbox.name = webs_user.username
limit 10;
此操作符合预期,并将非常快速地返回结果(在ms范围内)。但是对于我的查询,我需要它按日期或shoutID排序,以获得最新的。所以我添加了order by
声明:
select shoutID, date, name, message, webs_user.userID
from webs_shoutbox
left join webs_user on webs_shoutbox.name = webs_user.username
order by shoutID desc
limit 10;
突然这个查询需要13-14秒!?我对这个巨大的性能问题感到非常困惑。经过大量的阅读和谷歌搜索,我无法找到为什么它在主键字段上进行排序这么糟糕的工作。使用order by语句对webs_shoutbox
表进行选择时,它可以正常工作。它只与性能下降的join
结合使用。
可能导致这种情况的原因是什么?为什么要花这么长时间才能看似快速的操作(按PK /索引排序)?
答案 0 :(得分:1)
尝试以下
SELECT ws.shoutID, ws.date, ws.name, ws.message, webs_user.userID FROM
(select shoutID, date, name, message
from webs_shoutbox
order by shoutID
limit 10) as ws
left join webs_user on ws.name = webs_user.username
order by shoutID desc limit 10
答案 1 :(得分:0)
确保PK具有用于连接的哈希索引和用于排序的btree索引。
答案 2 :(得分:0)
试试这个(我希望这有效,因为将“order by”限制为一个表):
select t1.shoutID, t1.date, t1.name, t1.message, webs_user.userID
from (
select *
from webs_shoutbox
order by order by shoutID desc
limit 10
) as t1
left join webs_user on t1.name = webs_user.username
order by shoutID desc
limit 10;
一般来说,最好不要使用text / char / varchar字段作为关系手段(即外键)。使用整数字段并将它们编入索引更快。