使用order with with join时查询速度慢

时间:2015-05-25 18:51:02

标签: 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 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 /索引排序)?

3 个答案:

答案 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字段作为关系手段(即外键)。使用整数字段并将它们编入索引更快。