Mysql:索引實戰

 

MySQL主要提供2種方式的索引:B-Tree索引,Hash索引程序員

B樹索引具備範圍查找和前綴查找的能力,對於有N節點的B樹,檢索一條記錄的複雜度爲O(LogN)。至關於二分查找。面試

哈希索引只能作等於查找,可是不管多大的Hash表,查找複雜度都是O(1)。數據庫

顯然,若是值的差別性大,而且以等值查找(=、 <、>、in)爲主,Hash索引是更高效的選擇,它有O(1)的查找複雜度。緩存

若是值的差別性相對較差,而且以範圍查找(between and)爲主,B樹是更好的選擇,它支持範圍查找。函數

索引性能

不管是面試,仍是實際工做中,對於一個Java程序員來講,數據庫優化是避不開的一個技術點,關於數據庫的優化,在性能達不到要求的狀況下,我大體給出如下幾個方向:優化

(1)優化表結構,對經常使用字段和很是用的字段分開存儲3d

(2)優化SQL,合理使用索引code

(3)作數據庫讀寫分離,減小IO壓力,因爲數據庫對記錄作了持久化並存儲在磁盤上,對磁盤的I/O又是很是消耗性能的操做,所以讀、寫都在一個庫中會大大增長I/O的壓力blog

(4)嘗試使用緩存,不要讓數據都走數據庫

(5)對業務作垂直拆分

(6)對錶作水平拆分,這一步比較麻煩,要注意主鍵生成規則以及請求路由規則

以上6個點是有優先級的,本文關注的是第二點的索引部分。正確合理地使用索引對於數據庫性能提高是相當重要的,本文暫時不分析索引原理,只是從實戰的角度,總結一下索引的使用技巧,理論結合實踐,印象會更深一些。

固然,事前我已經創建了一張很簡單的student表並向表中插入了10萬條數據,SQL爲:

DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
  `s_id` int(11) NOT NULL AUTO_INCREMENT,
  `s_name` varchar(100) DEFAULT NULL,
  `s_age` int(11) DEFAULT NULL,
  `s_phone` varchar(30) DEFAULT NULL,
  PRIMARY KEY (`s_id`),
  KEY `s_name` (`s_name`)
) ENGINE=InnoDB, CHARSET=utf8;

 

使用普通索引與不使用普通索引的區別

先看一下不使用普通索引,進行查詢,執行SQL語句:

select * from student where s_name = "99999ssss";

看一下查詢時間:

花費了0.179秒,使用explain查看一下該條SQL語句的執行狀況:

分析幾個關鍵信息:

  • select_type:SIMPLE,這個不是很關鍵,只是表示這是一次簡單的查詢,沒有join,沒有union,沒有中間表
  • type:ALL,表示該次SQL進行了全表查詢
  • key:MySQL使用的索引名,這裏null表示這次SQL查詢MySQL並無使用索引
  • rows:這個是最關鍵的,表示此次SQL查詢了100665條記錄

OK,接下來給s_name這一列加上普通索引:

alter table student add index s_name(s_name);

看一下運行結果:

看到在s_name上加上索引以後,查詢速度立刻快了3倍以上。

從分析結果上來看,因爲這次SQL對列s_name使用了索引,所以rows只查了1條記錄,大大提高了查詢效率。

 

把索引創建在有大量重複數據的字段上

把索引創建在有大量重複數據的字段上,並不能有效地提高SQL效率,好比個人s_phone的取值爲"00000000"~"99999999",此時對s_phone作查詢,未加索引的時候:

看到這條select語句的查詢時間是0.05秒,而給s_phone字段加了索引以後:

反而變爲了0.064秒,並無顯著地提高查詢效率,反而更加緩慢。經過explain語句,發現這次SQL經過索引查詢了18000條rows,再去定位這18000多條數據,天然會慢一點。

這說明了,即便查詢的時候用到了索引,也未必能提高查詢的效率,索引創建在重複數據量不多的字段上效果才明顯,可是這也將致使索引的增大,不過大多數時候這並非太大的問題。

 

索引與like

不建議對索引列使用like語句,好比說執行如下兩句SQL:

select * from student where s_name like "%99999ssss%";
select * from student where s_name like "%99999ssss";

看一下explain出來的結果,都是同樣的:

發現沒有用到索引,這是對索引列使用like的限制,要對索引列使用like,通配符只能在結尾,開頭不能夠有任何的通配符,好比:

select * from student where s_name like "99999ssss%";

此時再explain看一下:

看到這麼實用like則使用到了索引,這不得不說是一個限制。

 

索引與函數

在索引列上使用MySQL函數也會致使索引失效,看一個例子:

select * from student where "99999ssss" = left(s_name, 9);

這條SQL語句很是好理解,查詢s_name列中從左邊開始截取9個字符後的字符串爲"99999ssss"的記錄,查看一下explain的結果:

結果很明顯,沒有用到索引,這代表對索引列使用函數將致使索引失效。

一個技巧是,依然使用=,可是索引列不使用函數而對常數項使用函數,這樣索引就有效了,固然這條語句是沒法這麼優化的。

相關文章
相關標籤/搜索