Mysql 将order by与联接结合使用时查询速度较慢
如下表所示:Mysql 将order by与联接结合使用时查询速度较慢,mysql,Mysql,如下表所示: 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 S
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\u user
表包含约4k条记录,webs\u shoutbox
包含约100k条记录
我想使用左连接查询数据库并从两个表中获取数据
:
select shoutID, date, name, message, webs_user.userID
from webs_shoutbox
left join webs_user on webs_shoutbox.name = webs_user.username
limit 10;
这将按照预期的方式运行,并将很快返回结果(在毫秒范围内)。但是对于我的查询,我需要按日期或截止日期排序,以便获得最新的。因此,我添加了一个orderby
语句:
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\u shoutbox
表上执行select时,效果良好。只有与join
结合使用,性能才会下降
这可能是什么原因造成的?为什么要花这么长时间才能完成看似快速的操作(在PK/索引上排序)?确保PK有一个用于连接的哈希索引和一个用于排序的btree索引。试试这个(我希望它能起作用,因为“order by”只限于一个表): 一般来说,最好不要使用text/char/varchar字段作为关系的手段(即外键)。使用整型字段并为其编制索引的速度更快。请尝试以下操作
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
当您选择just with LIMIT MySQL时,请选择前10条记录并停止。ORDERBY语句强制MySQL处理所有记录(并对它们进行排序),因此预计需要更多的时间time@Stan:此表的
主键shoutID
上的排序是否应该快速进行?应该如此。我可能错了,但申请加入结果时可能会很慢。您可以尝试从webs\u shoutbox获取10条有序记录,并将结果与webs\u用户连接。这应该更快。额外奖金-您不需要加入太多records@Stan:关于如何使用SQL实现这一点,您能给我一些提示或示例吗?我天真地希望mysql足够聪明,可以先进行排序和限制,然后再进行加入。我怎样才能用SQL来告诉mysql呢?作为回答,我发布了一个示例谢谢,这个查询正在做它应该做的事情(大约5毫秒)!我不知道使用这种子查询/语法。感谢您在执行加入之前演示如何限制结果。感谢您的回答。在修复了一些小的语法错误后,此查询的执行速度仍然非常慢(13秒)。用户Stan发布了一些相同的查询,但在子查询中限制了结果,这似乎是一个很好的解决方案。我知道使用text/varchar不是处理表之间关系的好方法,但我继承了这个数据库,如果它在这些字段上进行连接时表现足够好的话……我在子查询中使用了MS SQL Server语法。固定的。
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