並不是在所有的查詢條件下出現的列都需要新增索引。對於什麼時候新增b+樹索引,我的經驗是訪問表中很少一部分時,使用b+樹索引才有意義。對於性別字段,地區字段,型別字段,它們可取值的範圍很小,即低選著性。如:
select * from student where *** = '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 ***************************
table: info
non_unique: 1
key_name: index_link_family
seq_in_index: 1
column_name: link_family
collation: a
cardinality: 9385
sub_part: 255
packed: null
null: yes
index_type: btree
comment:
index_comment:
*************************** 3. row ***************************
table: info
non_unique: 1
key_name: index_date
seq_in_index: 1
column_name: date
collation: a
cardinality: 356639
sub_part: null
packed: null
null:
index_type: btree
comment:
index_comment:
表info大約有50萬行資料。info表上的date欄位,該字段是日期型別,欄位上有乙個index_date的非唯一索引。我們來看下面兩條sql的執行:
mysql> explain select * from info where date = '2006-07-26 15:56:01'\g;
*************************** 1. row ***************************
id: 1
select_type: ******
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;
*************************** 1. row ***************************
id: 1
select_type: ******
table: info
type: all
possible_keys: index_date
key: null
key_len: null
ref: null
rows: 356639
extra: using where
1 row in set (0.00 sec)
可以看到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 |
+--------+
1 row in set (0.00 sec)
可以看到我們將取出行的數大概是表的100%的行,因此優化器沒有選擇使用索引。mysql資料庫的優化器會通過explain的rows欄位預估查詢可能得到的行,如果大於某乙個值,則b+樹會選擇全表的掃瞄。至於這個值,根據我的經驗一般在20%。即當取出的資料量超過表中資料的20%,優化器就不會使用索引,而是進行全表的掃表。
但是預估的返回行數的值是不準確的,可以看到優化器判斷日期小於2006-07-26的行為356639,而實際的是452549 。
有時優化器的選擇並不完全是正確的,有時你更應該相信自己的判斷(可以通過force index(index_name)來執行判斷兩條語句執行的時間差別)。
索引之B樹 B 樹 B 樹 B 樹
原文索引之b樹 b 樹 b 樹 b 樹 b 樹即二叉搜尋樹 1.所有非葉子結點至多擁有兩個兒子 left 和right 2.所有結點儲存乙個關鍵字 3.非葉子結點的左指標指向小於其關鍵字的子樹,右指標指向大於其關鍵字的子樹 如 b樹的搜尋,從根結點開始,如果查詢的關鍵字與結點的關鍵字相等,那麼就命中...
B樹與B 樹索引
b 樹 資料庫結構使用樹的結構索引,從演算法邏輯上看,二叉查詢樹的查詢速度和比較次數都是最小的。資料庫的索引儲存在磁碟上,當資料量比較大的時候,索引的大小可能有幾個g 甚至更多。當我們利用索引查詢的時候,不可能把整個索引載入到記憶體,能做的只有逐一載入每乙個磁碟頁,磁碟頁對應索引樹的節點。當利用二叉...
B樹 B 樹及索引
b樹 每個節點都儲存key和data,所有節點組成這棵樹,並且葉子節點指標為null。b 樹 只有葉子節點儲存data,葉子節點包含了這棵樹的所有鍵值,葉子節點不儲存指標。後來在b 樹上加了順序訪問指標,也就是每個葉子節點增加乙個指向相鄰葉子節點的指標。可以像遍歷鍊錶一樣遍歷葉子節點。b 樹是資料庫...