并不是在所有的查詢條件下出現的列都需要添加索引。對于什麼時候添加B+樹索引,我的經驗是通路表中很少一部分時,使用B+樹索引才有意義。對于性别字段,地區字段,類型字段,它們可取值的範圍很小,即低選着性。如:
select * from student WHERE sex = 'M'
對于性别,可取值的範圍隻有'M','F'。對上述SQL語句得到的結果可能是該表的50%的資料,這時添加B+樹索引時完全沒有必要的。相反,如果某個字段的取值範圍很廣,幾乎沒有重複,即高選擇性,即此時使用B+樹索引時做合适的,例如姓名字段,基本上在一個應用中都不允許重名的出現。
是以,當通路高選擇性字段并從表中取出很少一部分時,對這個字段添加B+樹索引是非常有必要的。但是如果出現了通路字段是高選擇性的,但是取出的行資料占用表中大部分的資料時,這時MySQL資料庫就不會使用B+樹索引了,我們先來看一個例子:
mysql> show index from info\G;
*************************** 1. row ***************************
Table: info
Non_unique: 0
Key_name: PRIMARY
Seq_in_index: 1
Column_name: id
Collation: A
Cardinality: 356639
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
Comment:
Index_comment:
*************************** 2. row ***************************
Non_unique: 1
Key_name: index_link_family
Column_name: link_family
Cardinality: 9385
Sub_part: 255
Null: YES
*************************** 3. row ***************************
Key_name: index_date
Column_name: date
表info大約有50萬行資料。info表上的date字段,該字段是日期類型,字段上有一個index_date的非唯一索引。我們來看下面兩條SQL的執行:
mysql> explain select * from info where date = '2006-07-26 15:56:01'\G;
id: 1
select_type: SIMPLE
table: info
type: ref
possible_keys: index_date
key: index_date
key_len: 8
ref: const
rows: 2
Extra:
1 row in set (0.00 sec)
ERROR:
No query specified
可以看到使用了index_date這個索引,這也符合我們前面提到的高選擇性,選取表中很少行的原則。但是如果執行下面這條語句:
mysql> explain select * from info where date > '2006-07-26 15:56:01'\G;
type: ALL
key: NULL
key_len: NULL
ref: NULL
rows: 356639
Extra: Using where
可以看到possible_keys依然是index_date,但是實際優化器使用的索引key顯示的是NULL。為什麼?因為這不符合我們前面說的原則,雖然date這個字段的值是高選擇性的,但是我們取出的行占用了表中很大一部分。
mysql> select @a:=count(id) from info where date > '2006-07-26 15:56:01';
+---------------+
| @a:=count(id) |
| 452549 |
1 row in set (0.18 sec)
mysql> select @b:=count(id) from info ;
| @b:=count(id) |
| 452554 |
1 row in set (0.11 sec)
mysql> select @a/@b;
+--------+
| @a/@b |
| 1.0000 |
可以看到我們将取出行的數大概是表的100%的行,是以優化器沒有選擇使用索引。Mysql資料庫的優化器會通過EXPLAIN的rows字段預估查詢可能得到的行,如果大于某一個值,則B+樹會選擇全表的掃描。至于這個值,根據我的經驗一般在20%。即當取出的資料量超過表中資料的20%,優化器就不會使用索引,而是進行全表的掃表。
但是預估的傳回行數的值是不準确的,可以看到優化器判斷日期小于2006-07-26的行為356639,而實際的是452549 。
有時優化器的選擇并不完全是正确的,有時你更應該相信自己的判斷(可以通過force index(index_name)來執行判斷兩條語句執行的時間差别)。
本文轉自 kuchuli 51CTO部落格,原文連結:http://blog.51cto.com/lgdvsehome/1174516,如需轉載請自行聯系原作者