使用JOIN优化MySQL计数查询

时间:2014-01-10 16:44:44

标签: mysql sql query-optimization

我的查询大约需要20秒,我想了解是否有办法优化它。 表1:

CREATE TABLE IF NOT EXISTS `sessions` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `user_id` (`user_id`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=9845765 ;

表2:

CREATE TABLE IF NOT EXISTS `access` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `session_id` int(10) unsigned NOT NULL DEFAULT '0',
PRIMARY KEY (`id`),
KEY `session_id ` (`session_id `)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=9467799 ;

现在,我要做的是计算连接到一个用户的所有会话的所有访问权限,所以我的查询是:

SELECT COUNT(*)
FROM access
INNER JOIN sessions ON access.session_id=session.id
WHERE session.user_id='6';

这需要将近20秒......对于user_id 6,存储了大约3百万个会话。 我可以做些什么来优化该查询?

1 个答案:

答案 0 :(得分:1)

从会话表中更改此行:

KEY `user_id` (`user_id`)

对此:

KEY `user_id` (`user_id`, `id`)

这将为您做什么,允许您从索引中完成查询,而无需返回到原始表。实际上,您需要在user_id的会话表上执行索引扫描,并且对于每个项目,请返回到表中以查找用于访问表的连接的id。通过在索引中包含id,您可以跳过返回表格。

可悲的是,这会使你的插入更慢地进入该表,并且看起来这可能是一个出价协议,只给一个用户有3百万个会话。 Sql Server和Oracle将通过允许您在索引中包含id列而不实际对其进行索引,在插入时节省一些工作,并允许您为索引指定较低的填充因子来解决此问题,减少了在插入时重新构建或重新排序索引的需要,但MySql不支持这些。