mysql 索引- 筆記

索引mysql

   mysql最經常使用的索引結構是btree(O(log(n))),可是總有一些狀況下咱們爲了更好的性能但願能使用別的類型的索引。hash就是其中一種選擇,例如咱們在經過用戶名檢索用戶id的時候,他們老是一對一的關係,用到的操做符只是=而已,假如使用hash做爲索引數據結構的話,時間複雜度能夠降到O(1)。不幸的是,目前的mysql版本(5.6)中,hash只支持MEMORY和NDB兩種引擎,而咱們最經常使用的INNODB和MYISAM都不支持hash類型的索引。算法


一、BTree索引:sql

BTree(多路搜索樹,並非二叉的)是一種常見的數據結構。使用BTree結構能夠顯著減小定位記錄時所經歷的中間過程,從而加快存取速度。按照翻譯,B 一般認爲是Balance的簡稱。這個數據結構通常用於數據庫的索引,綜合效率較高。數據庫

B-Tree索引能夠被用在像=,>,>=,<,<=和BETWEEN這些比較操做符上。並且還能夠用於LIKE操做符,只要它的查詢條件是一個不以通配符開頭的常量。session

EXPLAIN select * from blog.my_user where `name` in ('rhythmk251','rhythmk2151','rhythmk7251','rhythmk685');
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
| 1 | SIMPLE | my_user | ALL | NULL | NULL | NULL | NULL | 778424 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------------+
1 row in set

  

添加 idx_name 索引:數據結構

ALTER TABLE blog.`my_user`
ADD INDEX `idx_name` (`name`) USING BTREE ;


mysql> EXPLAIN select * from blog.my_user where `name` in ('rhythmk251','rhythmk2151','rhythmk7251','rhythmk685');
+----+-------------+---------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+----------+---------+------+------+-------------+
| 1 | SIMPLE | my_user | range | idx_name | idx_name | 303 | NULL | 4 | Using where |
+----+-------------+---------+-------+---------------+----------+---------+------+------+-------------+


mysql> EXPLAIN select * from blog.my_user where `name` LIKE 'rhythmk830%';
+----+-------------+---------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+----------+---------+------+------+-------------+
| 1 | SIMPLE | my_user | range | idx_name | idx_name | 303 | NULL | 11 | Using where |
+----+-------------+---------+-------+---------------+----------+---------+------+------+-------------+
1 row in set

  任何一個沒有覆蓋全部WHERE中AND級別條件的索引是不會被使用的。也就是說,要使用一個索引,這個索引中的第一列須要在每一個AND組中出現。性能

mysql> EXPLAIN select * from blog.my_user where `name` LIKE 'rhythmk830%' or age>35;
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | my_user | ALL | idx_name | NULL | NULL | NULL | 7266 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
1 row in set
mysql> EXPLAIN select * from blog.my_user where `name` LIKE 'rhythmk830%' and age>35;
+----+-------------+---------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+----------+---------+------+------+-------------+
| 1 | SIMPLE | my_user | range | idx_name | idx_name | 303 | NULL | 11 | Using where |
+----+-------------+---------+-------+---------------+----------+---------+------+------+-------------+
1 row in set

有時候mysql不會使用索引,即便這個在可用的狀況下。例如當mysql預估使用索引會讀取大部分的行數據時。(在這種狀況下,一次全表掃描可能比使用索引更快,由於它須要更少的檢索)。然而,假如語句中使用LIMIT來限定返回的行數,mysql則會使用索引。由於當結果行數較少的狀況下使用索引的效率會更高。優化

mysql> EXPLAIN select * from blog.my_user where `name` <> 'rhythmk830' ;
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
| 1 | SIMPLE | my_user | ALL | idx_name | NULL | NULL | NULL | 7769 | Using where |
+----+-------------+---------+------+---------------+------+---------+------+------+-------------+
1 row in set

mysql> EXPLAIN select * from blog.my_user where `name` <> 'rhythmk830' limit 5;
+----+-------------+---------+-------+---------------+----------+---------+------+------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+---------+-------+---------------+----------+---------+------+------+-------------+
| 1 | SIMPLE | my_user | range | idx_name | idx_name | 303 | NULL | 5658 | Using where |
+----+-------------+---------+-------+---------------+----------+---------+------+------+-------------+
1 row in set

二、Hash 索引特徵:翻譯


Hash類型的索引有一些區別於以上所述的特徵:
精確查找很是快(包括= <> 和in),其檢索效率很是高,索引的檢索能夠一次定位,不像BTree 索引須要從根節點到枝節點,因此 Hash 索引的查詢效率要遠高於 B-Tree 索引。blog

不適合:

一、不適合模糊查詢和範圍查詢(包括like,>,<,between……and等)。因爲 Hash 索引比較的是進行 Hash 運算以後的 Hash 值,因此它只能用於等值的過濾,不能用於基於範圍的過濾,由於通過相應的 Hash 算法處理以後的 Hash 值的大小關係,並不能保證和Hash運算前徹底同樣;
二、不適合排序,數據庫沒法利用索引的數據來提高排序性能,一樣是由於Hash值的大小不肯定;
三、複合索引不能利用部分索引字段查詢,Hash 索引在計算 Hash 值的時候是組合索引鍵合併後再一塊兒計算 Hash 值,而不是單獨計算 Hash 值,因此經過組合索引的前面一個或幾個索引鍵進行查詢的時候,Hash 索引也沒法被利用。


三、備註:

一、索引列須要根據業務判斷 ,在where條件中出現的列。
二、使用索引須要考慮某列中值的分佈,好比性別,搜索 「男/女」 都會得出大約一半的行,全部索引沒有多大的用處。
三、使用短索引好處多多。對字符串進行索引的時候,應該指定一個前綴長度。索引長度小,節約索引空間及磁盤IO同時讓索引,短的值比較起來更快,同時Mysql 能夠在內存中存儲更多的值。
四、利用最左前綴。建立一個多列索引,可起幾個索引的做用。由於可利用索引最左邊的列來匹配行。這樣的列集稱爲最左前綴。
五、不要過分索引。 額外的索引須要佔用空間,並下降寫操做的性能。修改表的時候索引必須進行更新,有時可能須要重構,索引越多時間越長。索引太多,也可能致使MYSQL選擇不到最優索引。
六、INNODB 存儲引擎,記錄優先按主鍵保存,若是沒有主鍵,可是有惟一索引那麼就按惟一索引列保存。若是二者都沒有,那麼表中會生成一個內部列。按照這個列的順序保存,InnoDB普通索引都會保存主鍵,因此主鍵要儘量選擇較短的數據類型。

 七、儘可能避免NULL:應該指定列爲NOT NULL,除非你想存儲NULL。在MySQL中,含有空值的列很難進行查詢優化,由於它們使得索引、索引的統計信息以及比較運算更加複雜。你應該用0、一個特殊的值或者一個空串代替空值。

 八、使用--查看當前session全部已產生的profile  
      

mysql> show profiles;  
相關文章
相關標籤/搜索