2011-05-26 91 views
0

我們有一箇中央登錄,我們用它來支持多個網站。爲了存儲我們用戶的數據,我們有一個accounts表,該表存儲每個用戶帳戶,然後存儲每個站點的users表以獲取特定於站點的信息。奇怪的MySQL行爲 - 查詢優化幫助

我們注意到一個連接主鍵user_id上的表的查詢正在執行緩慢。我希望那裏的一些SQL專家能夠解釋爲什麼它使用WHERE來搜索users_site1表,並建議我們如何優化它。這裏是慢速查詢&的解釋結果:

mysql> explain select a.user_id as 'id',a.username,a.first_name as 'first',a.last_name as 'last',a.sex,u.user_id as 'profile',u.facebook_id as 'fb_id',u.facebook_publish as 'fb_publish',u.facebook_offline as 'fb_offline',u.twitter_id as 'tw_id',u.api_session as 'mobile',a.network from accounts a left join users_site1 u ON a.user_id=u.user_id AND u.status="R" where a.status="R" AND u.status="R" AND a.facebook_id='1234567890'; 
+----+-------------+-------+--------+----------------+---------+---------+-----------------------+-------+-------------+ 
| id | select_type | table | type | possible_keys | key  | key_len | ref     | rows | Extra  | 
+----+-------------+-------+--------+----------------+---------+---------+-----------------------+-------+-------------+ 
| 1 | SIMPLE  | u  | ALL | PRIMARY  | NULL | NULL | NULL     | 79769 | Using where | 
| 1 | SIMPLE  | a  | eq_ref | PRIMARY,status | PRIMARY | 4  | alltrailsdb.u.user_id |  1 | Using where | 
+----+-------------+-------+--------+----------------+---------+---------+-----------------------+-------+-------------+ 
2 rows in set (0.00 sec) 

下面是每個表的定義:

CREATE TABLE `accounts` (
    `user_id` int(9) unsigned NOT NULL AUTO_INCREMENT, 
    `username` varchar(40) DEFAULT NULL, 
    `facebook_id` bigint(15) unsigned DEFAULT NULL, 
    `facebook_username` varchar(30) DEFAULT NULL, 
    `password` varchar(20) DEFAULT NULL, 
    `profile_photo` varchar(100) DEFAULT NULL, 
    `first_name` varchar(40) DEFAULT NULL, 
    `middle_name` varchar(40) DEFAULT NULL, 
    `last_name` varchar(40) DEFAULT NULL, 
    `suffix_name` char(3) DEFAULT NULL, 
    `organization_name` varchar(100) DEFAULT NULL, 
    `organization` tinyint(1) unsigned DEFAULT NULL, 
    `address` varchar(200) DEFAULT NULL, 
    `city` varchar(40) DEFAULT NULL, 
    `state` varchar(20) DEFAULT NULL, 
    `zip` varchar(10) DEFAULT NULL, 
    `province` varchar(40) DEFAULT NULL, 
    `country` int(3) DEFAULT NULL, 
    `latitude` decimal(11,7) DEFAULT NULL, 
    `longitude` decimal(12,7) DEFAULT NULL, 
    `phone` varchar(20) DEFAULT NULL, 
    `sex` char(1) DEFAULT NULL, 
    `birthday` date DEFAULT NULL, 
    `about_me` varchar(2000) DEFAULT NULL, 
    `activities` varchar(300) DEFAULT NULL, 
    `website` varchar(100) DEFAULT NULL, 
    `email` varchar(150) DEFAULT NULL, 
    `referrer` int(4) unsigned DEFAULT NULL, 
    `referredid` int(9) unsigned DEFAULT NULL, 
    `verify` int(6) DEFAULT NULL, 
    `status` char(1) DEFAULT 'R', 
    `created` datetime DEFAULT NULL, 
    `verified` datetime DEFAULT NULL, 
    `activated` datetime DEFAULT NULL, 
    `network` datetime DEFAULT NULL, 
    `deleted` datetime DEFAULT NULL, 
    `logins` int(6) unsigned DEFAULT '0', 
    `api_logins` int(6) unsigned DEFAULT '0', 
    `last_login` datetime DEFAULT NULL, 
    `last_update` datetime DEFAULT NULL, 
    `private` tinyint(1) unsigned DEFAULT NULL, 
    `ip` varchar(20) DEFAULT NULL, 
    PRIMARY KEY (`user_id`), 
    UNIQUE KEY `username` (`username`), 
    KEY `status` (`status`), 
    KEY `state` (`state`) 
); 

CREATE TABLE `users_site1` (
    `user_id` int(9) unsigned NOT NULL, 
    `facebook_id` bigint(15) unsigned DEFAULT NULL, 
    `facebook_username` varchar(30) DEFAULT NULL, 
    `facebook_publish` tinyint(1) unsigned DEFAULT NULL, 
    `facebook_checkin` tinyint(1) unsigned DEFAULT NULL, 
    `facebook_offline` varchar(300) DEFAULT NULL, 
    `twitter_id` varchar(60) DEFAULT NULL, 
    `twitter_secret` varchar(50) DEFAULT NULL, 
    `twitter_username` varchar(20) DEFAULT NULL, 
    `type` char(1) DEFAULT 'M', 
    `referrer` int(4) unsigned DEFAULT NULL, 
    `referredid` int(9) unsigned DEFAULT NULL, 
    `session` varchar(60) DEFAULT NULL, 
    `api_session` varchar(60) DEFAULT NULL, 
    `status` char(1) DEFAULT 'R', 
    `created` datetime DEFAULT NULL, 
    `verified` datetime DEFAULT NULL, 
    `activated` datetime DEFAULT NULL, 
    `deleted` datetime DEFAULT NULL, 
    `logins` int(6) unsigned DEFAULT '0', 
    `api_logins` int(6) unsigned DEFAULT '0', 
    `last_login` datetime DEFAULT NULL, 
    `last_update` datetime DEFAULT NULL, 
    `ip` varchar(20) DEFAULT NULL, 
    PRIMARY KEY (`user_id`) 
); 

回答

1

在列facebook_idaccounts表中添加索引。

當前,MySql正在掃描整個users表,因爲它無法直接在account表中找到記錄。

0

的至少在accounts.user_iduser_site1.user_idaccounts.facebook_id創造3項指標。很可能user_id索引已經存在,因爲它們被定義爲PK。

+0

這兩個表的user_id字段是主鍵,所以他們應該已經被索引正確?根據EXPLAIN,這個問題似乎與在user_site1表上查找有關。這是不是意味着問題出在user_site1表上?我會假設MySQL會在帳戶表中找到該行,然後加入user_site1表,以便該表上的查找應該是即時的。我錯過了什麼? – 2011-05-26 02:41:58

0

也許是因爲你還沒有在你正在搜索的列上創建索引?嘗試索引連接語句中使用的列。沒有索引,你正在掃描所有的數據集。

CREATE INDEX accounts_user_id_index ON accounts (user_id); 
CREATE INDEX accounts.facebook_id_index ON accounts (status); 
CREATE INDEX user_site1.user_id_index ON user_site1 (user_id); 
0

您的查詢正在查找表accounts中的行,根據Facebook ID和帳戶「狀態」。你沒有任何幫助這個的索引,所以MySQL正在進行表掃描。我建議以下指標:

ALTER TABLE accounts ADD INDEX (facebook_id, user_id) 

如果你願意,你甚至可以包括在索引中的列status。這是否是一個好主意取決於是否有助於使索引成爲您計劃運行的任何其他查詢的優化程序的有吸引力的選擇。

PS。 「使用where」這個評論是正常的,並且在大多數查詢中都是可以預料的。這裏值得關注的事實是,MySQL沒有使用索引,並且認爲它必須檢查大量的行(當然,當你傳遞特定的ID號時不應該這樣)。