1、空間上的代價
乙個索引都為對應一棵b+樹,樹中每乙個節點都是乙個資料頁,乙個頁缺省會占用16kb的儲存空間,所以乙個索引也是會占用磁碟空間的。
2、時間上的代價
索引是對資料的排序,那麼當對表中的資料進行增、刪、改操作時,都需要去維護修改內容涉及到的b+樹索引。所以在進行增、刪、改操作時可能需要額外的時間進行一些記錄移動,頁面**、頁面**等操作來維護好排序。
由於是基於前面資料進行實戰,請檢視前面的專題;
聯合索引為bcd,下面情況均基於bcd聯合索引的場景下
select * from t1 where b =
1 and c =
1 and d =
1;
查詢優化器會分析這些查詢條件並且按照可以使用的索引中列的順序來決定先使用哪個查詢條件。
select * from t1 where b =1;
select * from t1 where b =
1 and c =
1;
下面這個sql是用不到索引的
select * from t1 where c =
1;
因為b+樹先是按照b列的值排序的,在b列的值相同的情況下才使用c列進行排序,也就是說b列的值不同的記錄中c的值可能是無序的。而現在你跳過b列直接根據c的值去查詢,這是做不到的。
select * from t1 where b like '%101%'
;
這種是用不到索引的,因為字串中間有』101』的字串並沒有排好序,所以只能全表掃瞄了。有時候我們有一些匹配某些字串字尾的需求,比方說某個表有乙個url列,該列中儲存了許多url:
www.qq.com假設已經對該url列建立了索引,如果我們想查詢以com為字尾的**的話可以這樣寫查詢條件:where url like 『%com』,但是這樣的話無法使用該url列的索引。
為了在查詢時用到這個索引而不至於全表掃瞄,我們可以把字尾查詢改寫成字首查詢,不過我們就得把表中的資料全部逆序儲存一下,也就是說我們可以這樣儲存url列中的資料:
moc.udiab.www
moc.elgoog.www
moc.qq.www
select * from t1 where b >
1 and b <
20000
;
由於b+樹中的資料頁和記錄是先按b列排序的,所以我們上邊的查詢過程其實是這樣的:
找到b值為1的記錄。
找到b值為20000的記錄。
由於所有記錄都是由鍊錶連起來的(記錄之間用單鏈表,資料頁之間用雙鏈表),所以他們之間的記錄都可以很容易的取出來
找到這些記錄的主鍵值,再到聚簇索引中回表查詢完整的記錄。
不過在使用聯合進行範圍查詢的時候需要注意,如果對多個列同時進行範圍查詢的話,只有對索引最左邊的那個列進行範圍查詢的時候才能用到b+樹索引,比如:
select * from t1 where b >
1 and c >
1;
對於同乙個聯合索引來說,雖然對多個列都進行範圍查詢時只能用到最左邊那個索引列,但是如果左邊的列是精確查詢,則右邊的列可以進行範圍查詢,比方說這樣:
select * from t1 where b =
1 and c >
1;
select * from t1 order by b, c, d;
這個查詢的結果集需要先按照b值排序,如果記錄的b值相同,則需要按照c來排序,如果c的值相同,則需要按照d排序。因為這個b+樹索引本身就是按照上述規則排好序的,所以直接從索引中提取資料,然後進行回表操作取出該索引中不包含的列就好了。
select b, c, d,
count(*
) from t1 group by b, c, d;
這個查詢語句相當於做了3次分組操作:
1)先把記錄按照b值進行分組,所有b值相同的記錄劃分為一組。
2)將每個b值相同的分組裡的記錄再按照c的值進行分組,將title值相同的記錄放到乙個分組裡。
3)再將上一步中產生的分組按照d的值分成更小的分組。
如果沒有索引的話,這個分組過程全部需要在記憶體裡實現,而如果有索引的話,正好這個分組順序又和b+樹中的索引列的順序是一致的,所以可以直接使用b+樹索引進行分組。
對於聯合索引有個問題需要注意,order by的子句後邊的列的順序也必須按照索引列的順序給出,如果給出order by c, b, d的順序,那也是用不了b+樹索引的。
同理,order by b,order by b, c這種匹配索引左邊的列的形式可以使用部分的b+樹索引。當聯合索引左邊列的值為常量,也可以使用後邊的列進行排序,比如這樣:
select * from t1 where b =
1 order by c, d;
asc、desc混用
對於使用聯合索引進行排序的場景,我們要求各個排序列的排序順序是一致的,也就是要麼各個列都是asc規則排序,要麼都是desc規則排序。
order by子句後的列如果不加asc或者desc預設是按照asc排序規則排序的,也就是公升序排序的。
select * from t1 order by b asc, c desc;
這個查詢是用不到索引的。
索引的選擇性(selectivity),是指不重複的索引值(也叫基數,cardinality)與表記錄數的比值:
選擇性 = 基數 / 記錄數
選擇性的取值範圍為(0, 1],選擇性越高的索引價值越大。如果選擇性等於1,就代表這個列的不重複值和表記錄數是一樣的,那麼對這個列建立索引是非常合適的,如果選擇性非常小,那麼就代表這個列的重複值是很多的,不適合建立索引。
用列的字首代替整個列作為索引key,當字首長度合適時,可以做到既使得字首索引的選擇性接近全列索引,同時因為索引key變短而減少了索引檔案的大小和維護開銷。
使用mysql官網提供的示例資料庫:
employees表只有乙個索引,那麼如果我們想按名字搜尋乙個人,就只能全表掃瞄了:查詢列沒有索引
explain select * from employees.employees where first_name='eric' and last_name='anido';
那麼可以對或建立索引,看下兩個索引的選擇性:
select count
(distinct
(first_name))/
count(*
) as selectivity from employees.employees;
--0.0042
select count
(distinct
(concat
(first_name, last_name)))
/count(*
) as selectivity from employees.employees;
--0.9313
顯然選擇性太低,選擇性很好,但是first_name和last_name加起來長度為30,有沒有兼顧長度和選擇性的辦法?可以考慮用first_name和last_name的前幾個字元建立索引,例如,看看其選擇性:
select count
(distinct
(concat
(first_name,
left
(last_name,3)
)))/
count(*
) as selectivity from employees.employees;
--0.7879
選擇性還不錯,但離0.9313還是有點距離,那麼把last_name字首加到4:
select count
(distinct
(concat
(first_name,
left
(last_name,4)
)))/
count(*
) as selectivity from employees.employees;
--0.9007
這時選擇性已經很理想了,而這個索引的長度只有18,比短了接近一半,建立字首索引的方式為:
alter table employees.employees add index `first_name_last_name4` (first_name,
last_name(4
));
字首索引兼顧索引大小和查詢速度,但是其缺點是不能用於order by和group by操作,也不能用於覆蓋索引。
• 索引列的型別盡量小
• 利用索引字串值的字首
• 主鍵自增
• 定位並刪除表中的重複和冗餘索引
• 盡量使用覆蓋索引進行查詢,避免回表帶來的效能損耗。
以上資訊來我在魯班學院學習的資料,魯班學院很不錯,值得報班
Mysql 索引(B樹或B 樹)
參考1 參考2myisam索引與innodb索引相比較 myisam支援全文索引 fulltext 壓縮索引,innodb不支援 innodb支援事務,myisam不支援 myisam順序儲存資料,索引葉子節點儲存對應資料行位址,輔助索引很主鍵索引相差無幾 innodb主鍵節點同時儲存資料行,其他輔...
MySQL索引之B 樹索引
b 樹索引是是目前關係型資料庫系統中查詢最為常用和最為有效的索引,b 樹的索引構造類似於二叉樹,根據鍵值 key value 快速找到資料。1 什麼是b 樹?首先,b 樹中的b並不是二叉樹 binary 的意思,這裡的b表示的是blance即平衡的意思。那麼b 樹其實就是平衡查詢樹。其滿足兩個條件 ...
Mysql索引B 樹,索引優化
索引是幫助mysql高效獲取資料的排好序的資料結構 mysql底層資料結構 b tree 特點 儲存引擎 99 innodb,早期myisam mylasm儲存引擎磁碟檔案 用途tb myisam.myi index,儲存的索引,b 樹 tb myisam.myd data,儲存的資料 tb myi...