理解MySQL數據庫覆蓋索引


話說有這么一個表:

CREATE TABLE `user_group` ( 
  `id` int(11) NOT NULL auto_increment, 
  `uid` int(11) NOT NULL, 
  `group_id` int(11) NOT NULL, 
  PRIMARY KEY  (`id`), 
  KEY `uid` (`uid`), 
  KEY `group_id` (`group_id`), 
) ENGINE=InnoDB AUTO_INCREMENT=750366 DEFAULT CHARSET=utf8

看AUTO_INCREMENT就知道數據並不多,75萬條。然后是一條簡單的查詢:

 

SELECT SQL_NO_CACHE uid FROM user_group WHERE group_id = 245;

 

很簡單對不對?怪異的地方在於:

  如果換成MyISAM做存儲引擎的時候,查詢耗時只需要0.01s,用InnoDB卻會是0.15s左右

  如果只是就這么點差距其實不是什么大不了的事,但是真實的業務需求比這個復雜,造成的差距也很大:MyISAM只需要0.12s,InnoDB則需要2.2s.,最終定位到問題症結是在這條SQL。

  Explain的結果是:

+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+ 
| id | select_type | table      | type | possible_keys | key      | key_len | ref   | rows | Extra | 
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+ 
|  1 | SIMPLE      | user_group | ref  | group_id      | group_id | 4       | const | 5544 |       | 
+----+-------------+------------+------+---------------+----------+---------+-------+------+-------+

看起來已經用上索引了,而這條SQL語句已經簡單到讓我無法再優化了。最后請前同事Gaston診斷了一下,他認為:數據分布上,group_id相同的比較多,uid散列的比較均勻,加索引的效果一般,但是還是建議我試着加了一個多列索引:

 

ALTER TABLE user_group ADD INDEX group_id_uid (group_id, uid);

 

 

 

 

然后,不可思議的事情發生了……這句SQL查詢的性能發生了巨大的提升,居然已經可以跑到0.00s左右了。經過優化的SQL再結合真實的業務需求,也從之前2.2s下降到0.05s。

再Explain一次:

+----+-------------+------------+------+-----------------------+--------------+---------+-------+------+-------------+ 
| id | select_type | table      | type | possible_keys         | key          | key_len | ref   | rows | Extra       | 
+----+-------------+------------+------+-----------------------+--------------+---------+-------+------+-------------+ 
|  1 | SIMPLE      | user_group | ref  | group_id,group_id_uid | group_id_uid | 4       | const | 5378 | Using index | 
+----+-------------+------------+------+-----------------------+--------------+---------+-------+------+-------------+

原來是這種叫覆蓋索引(covering index),MySQL只需要通過索引就可以返回查詢所需要的數據,而不必在查到索引之后再去查詢數據,所以那是相當的快!!但是同時也要求所查詢的字段必須被索引所覆蓋到,在Explain的時候,輸出的Extra信息中如果有“Using Index”,就表示這條查詢使用了覆蓋索引。

不過,還有一個無法解釋的問題就是,不用覆蓋索引的情況下,為什么用MyISAM就快那么多,而InnoDB就慢這么多呢?求真相……

原文出處:http://xiaobin.net/201109/strange-sql-performance-problem/


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM