2014-01-10 140 views
0

我有一個需要大約20秒的查詢,我想了解是否有方法來優化它。 表1:使用JOIN優化MySQL計數查詢

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百萬個會話。 我可以做什麼來優化該查詢?

+0

在表訪問中在列session_id上放置索引。 –

回答

1

改變這一行從會話表:

KEY `user_id` (`user_id`) 

要這樣:

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

這將完成你是讓你完成從索引的查詢,而無需返回原始表格。實際情況是,您需要在會話表上爲您的user_id執行索引掃描,並且對於每個項目回到表中找到用於加入訪問表的id。通過在索引中包含id,您可以跳過回到表格。

不幸的是,這會讓你的插入速度慢下來,看起來這可能是一個競標交易,因爲只有一個用戶有3百萬個會話。 Sql Server和Oracle會解決這個問題,它允許您在索引中包含id列,而無需實際編制索引,在插入時節省一些工作,並允許您爲索引指定較低的填充因子,從而減少需求在插入時重新構建或重新排序索引,但MySql不支持這些。

+0

注意:這對內部連接無關緊要,但我的直覺告訴我,你的表格順序倒退了:你真正想要做的是從會話開始並加入訪問,而不是從訪問開始,加入會議。再說一次,這真的不重要(因此只將它作爲註釋加入),但也許,也許,你可以欺騙查詢引擎,使其成爲一個更好的執行計劃。 –