Mysql索引設計原則:

推薦書籍:http://pan.baidu.com/s/1sjJIyRV

任務描述:

假設一高頻查詢以下
SELECT * FROM user WHERE area='amoy' AND sex=0 ORDER BY last_login DESC limit 30;
如何創建索引?描述考慮的過程mysql

user表以下:
初始化100W條數據,其中,area要經過IP查詢生成,sex爲 0,1 隨機sql

CREATE TABLE user (
id int(10) NOT NULL AUTO_INCREMENT COMMENT '自增編號',
username varchar(30) NOT NULL DEFAULT '0' COMMENT '用戶名',
password varchar(30) NOT NULL DEFAULT '0' COMMENT '密碼',
area varchar(30) NOT NULL COMMENT '地址',
sex int(10) NOT NULL COMMENT '性別1,男;2,女。',
last_login int(10) NOT NULL COMMENT '最近一次登陸時間戳',
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=892013 DEFAULT CHARSET=latin1性能

最終個人索引
(last_login,area)mysql索引

索引原則:

1.where和order by等的字段創建索引

2.使用惟一索引:對於last_login,area等字段重複的次數比較少,可使用索引;而sex無非就兩個值:性別1,男;2,不值得索引

3.多列索引:不要爲每個列單獨創建索引,這樣並不能將mysql索引的效率最大化。使用「索引合併策略」

4.選擇合理的索引列順序:索引列的順序意味着索引首先按照最左列進行排序,而後是第二列,以此類推。如(last_login,area)會先按照 last_login 進行排序,而後纔是area。

5.將選擇性最高的索引放到前面,也就是會所按照這個條件搜索到的數據最少,選擇性就越高,好比選擇性:last_login> area> sex。

6.索引不是越多越好,適合的索引能夠提升查詢效率,可是會下降寫入效率,根據項目保持二者的平衡性最好了。

總結上面,首先sex不適合創建索引,有沒有索引對於效率的提高意義不大,其次索引會按照最左列進行排序,所以將last_login放到最前面

測試過程:

user表
沒有任何索引的查詢相關日誌:
SELECT * FROM user WHERE area='美國ATT用戶' AND sex=0 ORDER BY last_login DESC limit 30; 0.57s
SELECT * FROM user WHERE area='泰國' AND sex=0 ORDER BY last_login DESC limit 30; 0.56s
SELECT * FROM user WHERE area='臺灣省臺灣大寬頻' AND sex=0 ORDER BY last_login DESC limit 30; 0.55s
SELECT * FROM user WHERE area='美國弗吉尼亞州' AND sex=0 ORDER BY last_login DESC limit 30; 0.59s
SELECT * FROM user WHERE area='德國奔馳汽車' AND sex=0 ORDER BY last_login DESC limit 30; 0.55s
SELECT * FROM user WHERE area='臺灣省中華電信' AND sex=0 ORDER BY last_login DESC limit 30; 0.55s
SELECT * FROM user WHERE area='韓國' AND sex=0 ORDER BY last_login DESC limit 30; 0.57s
SELECT * FROM user WHERE area='拉美地區' AND sex=0 ORDER BY last_login DESC limit 30; 0.58s
SELECT * FROM user WHERE area='美國紐約(Prudential)' AND sex=0 ORDER BY last_login DESC limit 30; 0.57s
SELECT * FROM user WHERE area='印度尼西亞' AND sex=0 ORDER BY last_login DESC limit 30; 0.57s
共花費時間:5.66s測試

創建索引area:
ALTER TABLE user ADD INDEX index_area (area) ;
SELECT * FROM user WHERE area='美國ATT用戶' AND sex=0 ORDER BY last_login DESC limit 30; 0.06s
SELECT * FROM user WHERE area='泰國' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='臺灣省臺灣大寬頻' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='美國弗吉尼亞州' AND sex=0 ORDER BY last_login DESC limit 30; 0.10s
SELECT * FROM user WHERE area='德國奔馳汽車' AND sex=0 ORDER BY last_login DESC limit 30; 0.04s
SELECT * FROM user WHERE area='臺灣省中華電信' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='韓國' AND sex=0 ORDER BY last_login DESC limit 30; 0.11s
SELECT * FROM user WHERE area='拉美地區' AND sex=0 ORDER BY last_login DESC limit 30; 0.20s
SELECT * FROM user WHERE area='美國紐約(Prudential)' AND sex=0 ORDER BY last_login DESC limit 30; 0.07s
SELECT * FROM user WHERE area='印度尼西亞' AND sex=0 ORDER BY last_login DESC limit 30; 0.04s
共花費時間:0.66s
可見,創建area之後對性能的影響是巨大的(5.66/0.66 約爲8.5758倍)
刪除索引:ALTER TABLE user DROP INDEX index_area;
刪除area索引起現時間又變成了0.57s日誌

創建last_login索引:
SELECT * FROM user WHERE area='美國ATT用戶' AND sex=0 ORDER BY last_login DESC limit 30; 0.03s
SELECT * FROM user WHERE area='泰國' AND sex=0 ORDER BY last_login DESC limit 30; 0.09s
SELECT * FROM user WHERE area='臺灣省臺灣大寬頻' AND sex=0 ORDER BY last_login DESC limit 30; 0.51s
SELECT * FROM user WHERE area='美國弗吉尼亞州' AND sex=0 ORDER BY last_login DESC limit 30; 0.01s
SELECT * FROM user WHERE area='德國奔馳汽車' AND sex=0 ORDER BY last_login DESC limit 30; 0.04s
SELECT * FROM user WHERE area='臺灣省中華電信' AND sex=0 ORDER BY last_login DESC limit 30; 0.07s
SELECT * FROM user WHERE area='韓國' AND sex=0 ORDER BY last_login DESC limit 30; 0.01s
SELECT * FROM user WHERE area='拉美地區' AND sex=0 ORDER BY last_login DESC limit 30; 0.01s
SELECT * FROM user WHERE area='美國紐約(Prudential)' AND sex=0 ORDER BY last_login DESC limit 30; 0.04s
SELECT * FROM user WHERE area='印度尼西亞' AND sex=0 ORDER BY last_login DESC limit 30; 0.06s
共花費時間:0.87s
一樣可以提高性能(5.66/0.87 約爲6.5057倍)code

創建sex索引:
ALTER TABLE user ADD INDEX index_sex (sex) ;
SELECT * FROM user WHERE area='美國ATT用戶' AND sex=0 ORDER BY last_login DESC limit 30; 0.87s
SELECT * FROM user WHERE area='泰國' AND sex=0 ORDER BY last_login DESC limit 30; 0.87s
SELECT * FROM user WHERE area='臺灣省臺灣大寬頻' AND sex=0 ORDER BY last_login DESC limit 30; 0.87s
SELECT * FROM user WHERE area='美國弗吉尼亞州' AND sex=0 ORDER BY last_login DESC limit 30; 0.89s
SELECT * FROM user WHERE area='德國奔馳汽車' AND sex=0 ORDER BY last_login DESC limit 30; 0.88s
SELECT * FROM user WHERE area='臺灣省中華電信' AND sex=0 ORDER BY last_login DESC limit 30; 0.87s
SELECT * FROM user WHERE area='韓國' AND sex=0 ORDER BY last_login DESC limit 30; 0.86s
SELECT * FROM user WHERE area='拉美地區' AND sex=0 ORDER BY last_login DESC limit 30; 0.88s
SELECT * FROM user WHERE area='美國紐約(Prudential)' AND sex=0 ORDER BY last_login DESC limit 30; 0.87s
SELECT * FROM user WHERE area='印度尼西亞' AND sex=0 ORDER BY last_login DESC limit 30; 0.87s
共花費時間:8.73s
一樣可以提高性能(5.66s/8.73 約爲0.6483倍)效率反而下降了??求解?
創建這個sex索引還不如不建。排序

刪除索引:
ALTER TABLE user DROP INDEX index_sex;
發現時間又變成了0.57s左右,索引

創建兩個單獨的索引:
ALTER TABLE user
ADD INDEX index_area (area) ,
ADD INDEX index_last_login (last_login) ;get

SELECT * FROM user WHERE area='美國ATT用戶' AND sex=0 ORDER BY last_login DESC limit 30; 0.09s
SELECT * FROM user WHERE area='泰國' AND sex=0 ORDER BY last_login DESC limit 30; 0.33s
SELECT * FROM user WHERE area='臺灣省臺灣大寬頻' AND sex=0 ORDER BY last_login DESC limit 30; 0.21s
SELECT * FROM user WHERE area='美國弗吉尼亞州' AND sex=0 ORDER BY last_login DESC limit 30; 0.01s
SELECT * FROM user WHERE area='德國奔馳汽車' AND sex=0 ORDER BY last_login DESC limit 30; 0.28s
SELECT * FROM user WHERE area='臺灣省中華電信' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='韓國' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='拉美地區' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='美國紐約(Prudential)' AND sex=0 ORDER BY last_login DESC limit 30; 0.03s
SELECT * FROM user WHERE area='印度尼西亞' AND sex=0 ORDER BY last_login DESC limit 30; 0.67s

發現創建兩個單獨的索引還不如只創建一個索引
刪除索引:
發現時間又變成了0.57s左右,

創建一個的聯合索引:
ALTER TABLE user
ADD INDEX index_last_login_area (last_login,area) ,
SELECT * FROM user WHERE area='美國ATT用戶' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='泰國' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='臺灣省臺灣大寬頻' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='美國弗吉尼亞州' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='德國奔馳汽車' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='臺灣省中華電信' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='韓國' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='拉美地區' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='美國紐約(Prudential)' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
SELECT * FROM user WHERE area='印度尼西亞' AND sex=0 ORDER BY last_login DESC limit 30; 0.00s
額,第二條數據這是怎麼了,我測試了5次都在這附近晃悠哈!
這尼瑪,找對索引啦!就該這麼創建,查詢不出來須要的時間啦!估計就是咱們須要的索引啦!!!!

刪除索引:
發現時間又變成了0.57s左右,

創建一個的聯合索引:
ALTER TABLE user
ADD INDEX index_sex_last_login_area (sex,last_login,area)
SELECT * FROM user WHERE area='美國ATT用戶' AND sex=0 ORDER BY last_login DESC limit 30; 0.18s
SELECT * FROM user WHERE area='泰國' AND sex=0 ORDER BY last_login DESC limit 30; 0.17s
SELECT * FROM user WHERE area='臺灣省臺灣大寬頻' AND sex=0 ORDER BY last_login DESC limit 30; 0.81s
SELECT * FROM user WHERE area='美國弗吉尼亞州' AND sex=0 ORDER BY last_login DESC limit 30; 0.01s
SELECT * FROM user WHERE area='德國奔馳汽車' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='臺灣省中華電信' AND sex=0 ORDER BY last_login DESC limit 30; 0.04s
SELECT * FROM user WHERE area='韓國' AND sex=0 ORDER BY last_login DESC limit 30; 0.01s
SELECT * FROM user WHERE area='拉美地區' AND sex=0 ORDER BY last_login DESC limit 30; 0.01s
SELECT * FROM user WHERE area='美國紐約(Prudential)' AND sex=0 ORDER BY last_login DESC limit 30; 0.03s
SELECT * FROM user WHERE area='印度尼西亞' AND sex=0 ORDER BY last_login DESC limit 30; 0.04s
sex怎麼老是你在拖後腿啊!把你調整到索引的最後一個吧!
刪除索引:
發現時間又變成了0.57s左右,

創建一個的聯合索引:
ALTER TABLE user
ADD INDEX index_last_login_area_sex (area,last_login,sex)
SELECT * FROM user WHERE area='美國ATT用戶' AND sex=0 ORDER BY last_login DESC limit 30; 0.03s
SELECT * FROM user WHERE area='泰國' AND sex=0 ORDER BY last_login DESC limit 30; 0.07s
SELECT * FROM user WHERE area='臺灣省臺灣大寬頻' AND sex=0 ORDER BY last_login DESC limit 30; 0.50s
SELECT * FROM user WHERE area='美國弗吉尼亞州' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='德國奔馳汽車' AND sex=0 ORDER BY last_login DESC limit 30; 0.05s
SELECT * FROM user WHERE area='臺灣省中華電信' AND sex=0 ORDER BY last_login DESC limit 30; 0.06s
SELECT * FROM user WHERE area='韓國' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='拉美地區' AND sex=0 ORDER BY last_login DESC limit 30; 0.02s
SELECT * FROM user WHERE area='美國紐約(Prudential)' AND sex=0 ORDER BY last_login DESC limit 30; 0.04s
SELECT * FROM user WHERE area='印度尼西亞' AND sex=0 ORDER BY last_login DESC limit 30; 0.06s

綜上所述:1.創建索引不必定可以加快查詢效率如sex這種給重複次數特別多的列增長索引如sex這種會下降查詢效率,具體的緣由有待查找
2.給重複次數比較少的列增長u謳吟仍是可以大幅度提升效率
3.給where和orderby以後的字段添加索引纔會加快查詢效率
4.爲每個列單獨創建索引,不能將索引的效率最大化,應該使用索引合併策略,即根據查詢條件,創建聯合索引
5.聯合索引的順序問題:將選擇性高的索引放到前面
6.根據資料創建索引意味着索引按照最左列進行排序,而後事第二列,以此類推。如(last_login ,area)就會按照last_login進行排序,而後纔是area
7.根據此次的這個查詢條件來講最好的索引是:ALTER TABLE userADD INDEX index_last_login_area (last_login,area)。

相關文章
相關標籤/搜索