[英]Odd MySQL Behavior - Query Optimization Help
我們有一個用於支持多個網站的中央登錄。 為了存儲我們用戶的數據,我們有一個accounts
表,該表存儲每個用戶帳戶,然后是每個站點的users
表,以獲取站點特定信息。
我們注意到,在主鍵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`)
);
在accounts
表中的facebook_id
列上添加索引。
當前,MySql 正在掃描整個users
表,因為它無法直接在account
表中找到記錄。
最少在accounts.user_id
、 user_site1.user_id
和accounts.facebook_id
上創建 3 個索引。 很可能user_id
索引已經存在,因為它們被定義為 PK。
也許是因為您沒有在要搜索的列上創建索引??? 嘗試索引連接語句中使用的列。 如果沒有索引,您將掃描所有數據集。
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);
您的查詢正在根據 Facebook ID 和帳戶“狀態”在表accounts
中查找行。 您沒有任何索引對此有幫助,因此 MySQL 正在執行表掃描。 我建議以下索引:
ALTER TABLE accounts ADD INDEX (facebook_id, user_id)
如果您願意,您甚至可以在索引中包含status
列。 這是否是一個好主意實際上取決於它是否有助於使索引成為您計划運行的任何其他查詢的優化器的有吸引力的選擇。
PS。 注釋“使用 where”是正常的,並且在大多數查詢中都是可以預期的。 這里要關心的是,MySQL 沒有使用索引,它認為它必須檢查大量行(當你傳遞一個特定的 ID 號時肯定不應該是這種情況)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.