索引是什麼?相信大家都用過字典。你是怎麼從厚厚的新華字典中找到你需要找到的那個字的呢?又是怎麼從一本書中快速定位到你需要的章節?
我們都是通過書中的目錄,然後根據目錄中的頁碼定位到我們要的資訊。
同樣在mysql中也是這樣為我們準備了乙份目錄。當你去通過sql語句查詢的時候用不用索引,以及怎麼用索引。決定了你的查詢所耗費的時間。
在優化我們的應用的時候,首先應該考慮的是使用索引,試圖通過其它途徑來提高效能則純粹是在浪費時間。你應該先使用索引最大程度的改進效能,再考慮看看是否有其它的技術可以使用。
所以,索引是什麼?—— 是乙份經過排序的目錄表。
沒有索引的資料表:乙個沒有索引的資料表,就是乙個無序的資料行的集合。我們要從中找到符合條件的一行記錄,需要掃瞄整個表,挨個詢問,你是不是?是,留下。不是,找下乙個。當然了,通過sql查詢出來的資料行也是乙個集合。
存在索引的資料表:先看一張資料表
當我們給id
新增索引的時候生成的索引檔案可能是這個樣子的
存在索引的資料表,在查詢過程中就不需要再去掃瞄整張表中的資料行了。比如我們給id
新增了乙個索引,當我們要查詢的條件是:id=13
的時候,我們開始掃瞄索引,並找到了3條符合條件的記錄行。當掃瞄到達了id為14的資料行的時候,這個值高於我們搜尋的值。由於索引是經過分類的,所以當讀取到包含14的記錄時,我們就知道不再會有與id=13
相吻合的資料,從而不再進行掃瞄。
在上面查詢索引檔案的時候,使用的是線性掃瞄,(從第乙個,到認為之後不符合條件的最後乙個)。另一種方式是定位演算法的使用,它們可以不經過線性掃瞄就可以直接定位到第乙個匹配項。從而節省了大量的搜尋時間。各種資料庫使用各種各樣的技術來迅速的找到索引值。而我們只需要知道的是索引這個工具用來幹啥,怎麼用就行了。
在上面的例子中,可以看出不使用索引跟使用索引進行查詢時它們的差別。如果還不能給你震撼感,那麼舉個例子:
假設你有三張沒有索引的資料表:t1、t2、t3。每張表有1000條資料行。我們要找出這三張表中具有相同數值的所有資料行的組合:
select t1.i1,t2.i2,t3.i3
from t1 inner join t2 inner join t3
where t1.i1 = t2.i2 and t2.i2 = t3.i3;
這個查詢的結果應該有1000個資料行,每行都包含3個相等的資料行。當我們不使用索引來查詢的時候,t1表的每行記錄我們都需要拿到
t2表中進行全表掃瞄,同樣t2表中符合的記錄,我們需要拿到t3表進行全表掃瞄。
這樣子得到符合的記錄可能的組合是:1000x1000x1000(10億)種,比匹配的數目多100萬倍。
為資料表編制索引可以很大程度的提高查詢的速度,它可以像下面這樣處理查詢:
1. 從資料表t1中選擇第乙個資料行,看這個資料行包含什麼樣的值。
2. 對資料表t2使用索引,直接找到與t1表中相匹配的資料行,類似的對資料表t3使用索引,直接找到與t1表相匹配的資料行
3. 對資料表t1的下乙個資料行重複上面的過程,直到檢查完t1表中所有的資料行。
使用索引後對t1表還是進行了全表掃瞄,但是能夠對t2、t3資料表帶索引搜尋。直接將那些資料行挑選出來,這種查詢執行速度比不帶索引的查詢執行快100萬倍。
對於不同的儲存引擎,索引實現的細節有所不同。對與myisam
資料表來說,資料表的資料行是在資料檔案裡。而索引值是在索引檔案裡。乙個資料表可以有多個索引,所有的索引都儲存在同乙個索引檔案裡。索引檔案裡的每個索引都是由分類的關鍵記錄陣列組成的。這些陣列用於快速訪問資料表檔案。
innodb
儲存引擎使用的是乙個表空間,在這個表空間裡,它管理著所有的innodb
型別的資料表的資料和索引的儲存。我們也可以通過配置使每個使用innodb
引擎的資料表建立自己的乙個表空間。
找到這篇文章需要新增的位置,插入進去。
更新這本書的目錄,使讀者可以快速的定位到這篇文章。
此時你會發現乙個問題,當你新增的文章越來越多的時候,你的目錄也會變得越來越厚。對了~索引會占用一定的磁碟空間。
另外的是,每次新增一篇文章你都得更新下目錄。會占用一定的時間。索引也一樣,所以當涉及到對有索引的資料表進行插入、刪除、更新,等操作的時候,索引會降低這些操作的效能。之所以會出現這種情況是由於對一條資料行進行插入操作,不僅要修改資料表中的資料行,還要求所修改的資料行的索引要做出改變。乙個資料表有越多的索引,需要做出的改變就越多,平均效能下降就越多。
絕大多數表都是讀操作多過於寫操作,但對那些寫操作次數比較多的表來說,索引更新的開銷可能會非常大。
儘管有上面所提到的時間和空間上的缺點,但是你見過一本書沒有目錄嗎?所以在使用索引的時候需要均衡的考慮,是不是非用不可。可以多進行幾次基準測試,當然了,如果時間允許的話。
盡量為用來搜尋、分類或分組的資料列編制索引你有一張資料表,該怎麼具體為哪乙個字段新增索引,能夠讓mysql的優化器找到它,並使用它?
盡量為用來搜尋、分類或分組的資料列編制索引。不要為作為顯式或輸出的資料列編制索引。也就是說最適合有索引的資料列
是那些在:
1. 出現在 where 子句中的資料列
2. 在聯結子句**現的資料列 如:select * from atable inner join btable on atable.id = btable.id;
3. 在 order by 或 group by 子句**現的資料列。
根據 select 子句**現的資料列僅僅用來輸出顯式的字段最好不要有索引。
考慮資料列的維度資料列的維度等於它所容納的非重複值的個數。比如說有個資料列裡面的值分別是:
1,5,19,75,5,1
。它的維度就是4
(去掉重複值後)。資料列的維度的最大值等於表裡資料行的個數。資料列的維度值越高包含的重複值就越少,索引的使用效果也就越好。
以前在設計表的時候我也糾結過到底要不要給資料表中的status(狀態)
加索引。因為這個欄位是經常在where
語句**現的。而實際上這種可以用enum
資料型別的字段當他在資料表中的資料行出現頻率超過30%
後mysql的查詢優化器通常會跳過索引,而進行全表掃瞄。現在的優化器更複雜,能夠把其它因素考慮進來。百分比不再是mysql決定進行一次全表掃瞄而不使用索引的唯一依據了。所以當你認為該資料列的維度確實不是太底的時候可以用desc
或者explain
與驗證下優化器到底有沒有使用到索引。
關於復合索引當你建立了乙個
n
個資料列的復合索引時,實際上就建立了mysql能夠使用的n
個索引。怎麼說呢?比如:
key `indexname` (`column1`,`column2`,`column3`);
注意索引的順序,在查詢中能夠使用的索引順序如下:
column1, column2, column3
column1, column2
column1
mysql不能使用沒有包含最左邊索引欄位的索引(column1
)。比如:column2,column3
。猜想下如果使用column1,column3
呢?mysql 能不能用到索引?答案是可以的,但也只用到了column1
這個索引,column3
這個索引時用不到的。也就是說mysql能夠使用到column1
去縮小匹配的範圍,但是這個索引不能用於這個值的組合。 mysql索引及優化
mysql的索引可以從不同的維度來進行區分,如下 這是最基本的索引型別,基於普通字段建立的索引,沒有任何限制。與 普通索引 類似,不同的就是 索引欄位的值必須唯一,但允許有空值 在建立或修改表時追加唯一 約束,就會自動建立對應的唯一索引。它是一種特殊的唯一索引,不允許有空值。在建立或修改表時追加主鍵...
MySQL優化(三) 索引原理及索引優化
b tree索引,它是目前關係型資料庫中查詢資料最為常用和有效的索引,大多數儲存引擎都支援這種索引。使用b tree這個術語,是因為mysql在create table或其它語句中使用了這個關鍵字,但實際上不同的儲存引擎可能使用不同的資料結構,比如innodb就是使用的b tree。中的b是指bal...
MySQL索引建立及優化
聯合索引中 索引建立在離散度大的字段上面 離散度指利用count distinct 獲取欄位的唯一值,唯一值越多的離散度越大 索引的優化 重複及冗餘索引 重複索引 指相同的列以相同的順序建立的同型別的索引,如下表 create table if not exists test id smallint...