MySQL数据库索引
目錄
索引是什么
索引有哪些結構/索引常見的模型
B+樹索引
數據庫有哪些索引
唯一索引
聚簇索引與非聚簇索引
全文索引
索引的最左前綴原則
索引下推
使用索引一定能提高查詢性能嗎?
哪些情況下設置了索引但是無法使用
哪些情況下需要設置索引、哪些情況下不需要
什么情況下應該使用組合/聯合索引而非單獨索引
MySQL中索引是如何組織數據的存儲的
Mysql索引原理
Mysql是如何根據索引查詢數據的
普通索引和唯一索引,應該怎么選擇?
索引是什么
索引是對數據庫表中一個或多個列的值進行排序的結構,是幫助MySQL高效獲取數據的數據結構
你也可以這樣理解:索引就是加快檢索表中數據的方法。數據庫的索引類似于書籍的索引。在書籍中,索引允許用戶不必翻閱完整本書就能迅速地找到所需要的信息。在數據庫中,索引也允許數據庫程序迅速地找到表中的數據,而不必掃描整個數據庫。
MySQL數據庫幾個基本的索引類型:普通索引、唯一索引、主鍵索引、全文索引
1.索引加快數據庫的檢索速度
2.索引降低了插入、刪除、修改等維護任務的速度
3.唯一索引可以確保每一行數據的唯一性
4.通過使用索引,可以在查詢的過程中使用優化隱藏器,提高系統的性能
5.索引需要占物理和數據空間
索引有哪些結構/索引常見的模型
1. 哈希表:一種以鍵-值(key-value)存儲數據的結構,我們只要輸入待查找的值即key,就可以找到其對應的值即Value。哈希的思路很簡單,把值放在數組里,用一個哈希函數把key換算成一個確定的位置,然后把value放在數組的這個位置。如果出現hash沖突,則在沖突的value位置使用鏈表進行連接。
? ? 適用場景:等值查詢,如Memcached及其他一些NoSQL引擎
? ??
2.?有序數組
? ? 適用場景:只適用于靜態存儲引擎。用于等值查詢和范圍查詢(ID值必須是遞增的)
? ??
3. 搜索樹:左子節點小于父節點、父節點小于右子節點。Innodb使用B+樹,為什么數據庫使用B+樹作為索引?
問:為什么采用B+樹?這和Hash索引比較起來有什么優缺點嗎?
答:因為Hash索引底層是哈希表,哈希表是一種以key-value存儲數據的結構,所以多個數據在存儲關系上是完全沒有任何順序關系的,所以,對于區間查詢是無法直接通過索引查詢的,就需要全表掃描。所以,哈希索引只適用于等值查詢的場景。而B+樹是一種多路平衡查詢樹,所以他的節點是天然有序的(左子節點小于父節點、父節點小于右子節點),所以對于范圍查詢的時候不需要做全表掃描
1、哈希索引適合等值查詢,但是無法進行范圍查詢?
2、哈希索引沒辦法利用索引完成排序?
3、哈希索引不支持多列聯合索引的最左匹配規則?
4、如果有大量重復鍵值的情況下,哈希索引的效率會很低,因為存在哈希碰撞問題
B+樹索引
我們舉個例子,假設我們有一個主鍵列為ID的表,表中有字段k,并且在k上有索引。
表中R1~R5的(ID,k)值分別為(100,1)、(200,2)、(300,3)、(500,5)和(600,6),兩棵樹的示例示意圖如下。
主鍵索引的葉子節點存的是整行數據。在InnoDB里,主鍵索引也被稱為聚簇索引(clustered index)。
非主鍵索引的葉子節點內容是主鍵的值。在InnoDB里,非主鍵索引也被稱為二級索引(secondary index)。
? ? PS:主鍵長度越小,普通索引的葉子節點就越小,普通索引占用的空間也就越小。
基于主鍵索引和普通索引的查詢有什么區別?
- 如果語句是select * from T where ID=500,即主鍵查詢方式,則只需要搜索ID這棵B+樹;
- 如果語句是select * from T where k=5,即普通索引查詢方式,則需要先搜索k索引樹,得到ID的值為500,再到ID索引樹搜索一次。這個過程稱為回表。
也就是說,基于非主鍵索引的查詢需要多掃描一棵索引樹。因此,我們在應用中應該盡量使用主鍵查詢。
索引維護
? ? 對于主鍵不是遞增的表,在插入數據時,如新插入數據ID值為400,則需要邏輯上挪動后面的數據,空出位置。
? ? 而更糟的情況是,如果R5所在的數據頁已經滿了,根據B+樹的算法,這時候需要申請一個新的數據頁,然后挪動部分數據過去。這個過程稱為頁分裂。
? ? 除了性能外,頁分裂操作還影響數據頁的利用率。原本放在一個頁的數據,現在分到兩個頁中,整體空間利用率降低大約50%。當
? ? 然有分裂就有合并。當相鄰兩個頁由于刪除了數據,利用率很低之后,會將數據頁做合并。合并的過程,可以認為是分裂過程的逆過程。
數據庫有哪些索引
在MySql數據庫中,有四種索引:聚集索引(主鍵索引)(聚簇索引)、普通索引、唯一索引以及全文索引(FUNLLTEXT INDEX)
索引又可分為聚簇索引和非聚簇索引兩種
唯一索引
一種索引,不允許具有索引值相同的行,從而禁止重復的索引或鍵值。系統在創建該索引時檢查是否有重復的鍵值,并在每次使用 INSERT 或 UPDATE 語句添加數據時進行檢查。
CREATE UNIQUE CLUSTERED INDEX myclumn_cindex ON mytable(mycolumn)
聚簇索引與非聚簇索引
可以理解為主鍵索引與普通索引
| 聚簇索引:是對磁盤上實際數據重新組織以按指定的一個或多個列的值排序的算法。特點是存儲數據的順序和索引順序一致,且一個表只能有一個聚簇索引,因為物理存儲只能有一個順序。主鍵索引一般都是聚簇索引 非聚簇索引:表數據存儲順序與索引順序無關。對于非聚簇索引,葉結點包含索引字段值及指向數據頁數據行的邏輯指針,其行數量與數據表行數據量一致。非聚簇索引記錄的物理順序與邏輯順序沒有必然的聯系,與數據的存儲物理結構沒有關系;一個表對應的非聚簇索引可以有多條,根據不同列的約束可以建立不同要求的非聚簇索引; 一般情況下主鍵會默認創建聚簇索引,且一張表只允許存在一個聚簇索引。因為物理存儲只能有一個順序。 聚簇索引的葉子節點就是數據節點(Innodb的B+樹的主鍵對應的數據節點),而非聚簇索引的葉子節點仍然是索引節點,只不過有指向對應數據塊的指針。 聚簇索引主鍵的插入速度要比非聚簇索引主鍵的插入速度慢很多。 相比之下,聚簇索引適合排序,非聚簇索引不適合用在排序的場合。因為聚簇索引本身已經是按照物理順序放置的,排序很快。非聚簇索引則沒有按序存放,需要額外消耗資源來排序。 建立聚簇索引的語句: CREATE CLUSTER INDEX index_name ON table_name(column_name1,...); |
問:主鍵索引查詢只會查一次,而非主鍵索引一定需要回表查詢多次嗎?
答:通過覆蓋索引也可以只查詢一次
覆蓋索引(covering index)指一個查詢語句的執行只用從索引中就能夠取得,不必從數據表中讀取。也可以稱之為實現了索引覆蓋。
當一條查詢語句符合覆蓋索引條件時,MySQL只需要通過索引就可以返回查詢所需要的數據,這樣避免了查到索引后再返回表操作,減少I/O提高效率。
如,表covering_index_sample中有一個普通索引 idx_key1_key2(key1,key2)。
當我們通過SQL語句:select key2 from covering_index_sample where key1 = 'keytest';的時候,就可以通過覆蓋索引查詢,無需回表。
注:如果這個覆蓋索引是一個前綴索引,那么它依然需要回表,因為系統并不確定前綴索引的定義是否截斷了完整信息。
問:以下重建索引的步驟是否存在問題?
重建普通索引 k
alter table T drop index k; alter table T add index(k);重建主鍵索引
alter table T drop primary key; alter table T add primary key(id);答:重建索引k的做法是合理的,可以達到省空間的目的。但是,重建主鍵的過程不合理。不論是刪除主鍵還是創建主鍵,都會將整個表重建。所以連著執行這兩個語句的話,第一個語句就白做了。這兩個語句,可以用這個語句代替 : alter table T engine=InnoDB。
全文索引
| 全文索引(也稱全文檢索)是目前搜索引擎使用的一種關鍵技術。它能夠利用【分詞技術】等多種算法智能分析出文本文字中關鍵詞的頻率和重要性,然后按照一定的算法規則智能地篩選出我們想要的搜索結果。 select * from 表名 where?標題 like '%xxx%' or 內容?like '%xxx%' or 作者?like '%xxx%'; 這種搜索效率無比底下 全文索引是為了使得“關鍵詞搜索”功能更加的高效能。 我們有這么一張數據表:? 文章id 文章標題 文章內容 1 超級塞亞人 ?我是超級塞亞人我喜歡吃蘋果,我不是233大國的人,也不是地球人 2 我233大國威武,我233大國13億人,我233大國 3 我喜歡游泳 游泳有很多好方法 4 動畫片 我兒子喜歡看動畫片,尤其是七龍珠,因為里面有塞亞人,而且塞亞人喜歡吃蘋果,他們不是地球人 5 運動 我喜歡運動,喜歡跑步,喜歡游泳,喜歡健身,喜歡xxoo 6 打炮 我是一個二戰的老兵,這是我的回憶錄,我最幸福的時光就是在233大國吃著蘋果打炮 7 。。。 ? 8 。。。 ? 9 。。。 ? 然后,根據以上的文章內容,如果建立了一個索引文件(這里忽略索引文件的數據結構,僅僅以一種易于理解的方式呈現):? 關鍵詞 ? 文章id 塞亞人 ? ?1,4 蘋果 ? ? ?1,4,6 233大國 ? ? ?1,2,6 地球 ? ? ? ?1,4 游泳 ? ? ? ?3,5 七龍珠 ? ? ?4 喜歡 ? ? 1,4,5,6 ?? 那么當我想搜索 ?“塞亞人”的時候,這個索引文件直接告訴我在文章id為1和4的文章里有這個詞。? 這個索引文件就是“全文索引”。 如何使用全文索引和分詞的方式來幫助優化你的搜索呢? 需要工作的程序:索引程序,分詞程序,數據庫。? 工作原理:? 1、索引程序從數據庫讀取數據,比如上面例子中的數據表,索引程序通過sql語句:select 文章id,文章標題,文章內容 from 文章表.獲得文章的相關數據? 2、索引程序對需要索引的內容進行“分詞”,而這里的分詞就是調用分詞程序啦!? 3、索引程序對分好詞的一個個詞條加入索引文件。 在你寫的代碼里,原來到數據庫----like %xxx%-----的語句就變成了到索引文件里去查找,從而找到相應的數據(這點相信你已經理解啦!) 創建全文索引的兩種方法: 1.在建表語句中 2.在已知表中 ALTER TABLE article ADD FULLTEXT INDEX fulltext_article(title,content); 具體如何使用全文索引呢? 不用全文索引時的寫法:SELECT * FROM article WHERE content LIKE ‘%查詢字符串%’; 使用全文索引:SELECT * FROM article WHERE MATCH(title,content) AGAINST (‘查詢字符串’); 注意: 1、MySql自帶的全文索引只能對英文進行全文檢索,目前無法對中文進行全文檢索。如果需要對包含中文在內的文本數據進行全文檢索,我們需要采用Sphinx(斯芬克斯)/Coreseek技術來處理中文。 2、使用MySql自帶的全文索引時,如果查詢字符串的長度過短將無法得到期望的搜索結果。MySql全文索引所能找到的詞默認最小長度為4個字符。另外,如果查詢的字符串包含停止詞,那么該停止詞將會被忽略。 3、如果可能,請盡量先創建表并插入所有數據后再創建全文索引,而不要在創建表時就直接創建全文索引,因為前者比后者的全文索引效率要高。 |
索引的最左前綴原則
在MySQL建立聯合索引時會遵守最左前綴匹配原則,即最左優先,在檢索數據時從聯合索引的最左邊開始匹配。
索引下推
Index Condition Pushdown (ICP) ,Mysql 5.6添加,用于優化數據查詢。
索引條件下推優化可以減少存儲引擎查詢基礎表的次數,也可以減少MySQL服務器從存儲引擎接收數據的次數。?
用下面這種場景進行介紹
假設有如下查詢語句:select * from tuser where name like '張%' and age=10 and ismale=1;? (有聯合索引 name,age)
我們知道了前綴索引規則,所以這個語句在搜索索引樹的時候,只能用 “張”
以下是Mysql 5.6 之前的查詢流程:
以下是Mysql 5.6 時的查詢流程:(使用了索引下推)
InnoDB在(name,age)索引內部就判斷了age是否等于10,對于不等于10的記錄,直接判斷并跳過。在我們的這個例子中,只需要對ID4、ID5這兩條記錄回表取數據判斷,就只需要回表2次。
使用索引一定能提高查詢性能嗎?
通常,通過索引查詢數據比全表掃描要快,但是我們也必須注意到它的代價.
索引需要空間來存儲,也需要定期維護, 每當有記錄在表中增減或索引列被修改時,索引本身也會被修改。這意味著每條記錄的INSERT,DELETE,UPDATE將為此多付出4,5次的磁盤I/O.
索引不但會使得插入和修改的效率降低,而且在查詢的時候,有一個查詢優化器,太多的索引會讓優化器困惑,可能沒有辦法找到正確的查詢路徑,從而選擇了慢的索引。
索引范圍查詢(INDEX RANGE SCAN)適用于兩種情況:
? ? 1.基于一個范圍的檢索,一般查詢返回結果集小于表中記錄數的30%
? ? 2.基于非唯一性索引的檢索
? ? 3.直接晉升為覆蓋索引,避免多次查表
哪些情況下設置了索引但是無法使用
根本原因是查詢優化器決定不使用索引:
一條SQL語句的查詢,可以有不同的執行方案,至于最終選擇哪種方案,需要通過優化器進行選擇,選擇執行成本最低的方案。在一條單表查詢語句真正執行之前,MySQL的查詢優化器會找出執行該語句所有可能使用的方案,對比之后找出成本最低的方案。這個成本最低的方案就是所謂的執行計劃。優化過程大致如下:
1、根據搜索條件,找出所有可能使用的索引?
2、計算全表掃描的代價?
3、計算使用不同索引執行查詢的代價?
4、對比各種執行方案的代價,找出成本最低的那一個
有時候查詢語句沒有按照索引的要求來也會導致無法使用索引,如下:
哪些情況下需要設置索引、哪些情況下不需要
| 需要: 1).主鍵自動建立唯一索引 不需要: 1).表記錄太少 4).where條件里用不到的字段不創建索引 |
什么情況下應該使用組合/聯合索引而非單獨索引
| 假設有條件語句A=a AND B=b,如果A和B是兩個單獨的索引,在AND條件下只有一個索引起作用,對于B則要逐個判斷,而如果使用組合索引(A, B),只要遍歷一棵樹就可以了,大大增加了效率。但是對于A=a OR B=b,由于是 或 的關系,因而組合索引是不起作用的,此時可以使用單獨索引,這個時候,兩個索引可以同時起作用。 在建立聯合索引的時候,如何安排索引內的字段順序? ? ? 評估標準是:索引的復用能力。因為可以支持最左前綴,所以當已經有了(a,b)這個聯合索引后,一般就不需要單獨在a上建立索引了。 ? ? 因此,第一原則是,如果通過調整順序,可以少維護一個索引,那么這個順序往往就是需要優先考慮采用的。 ? ? 那么,如果既有聯合查詢,又有基于a、b各自的查詢呢?查詢條件里面只有b的語句,是無法使用(a,b)這個聯合索引的,這時候你不得不維護另外一個索引,也就是說你需要同時維護(a,b)、(b) 這兩個索引。 ? ? 這時候,我們要考慮的原則就是空間了。也就是說,如果b的大小是比較小的,如boolean、int類型, 那么可以再多建立一個b索引 下面通過一個例子來加深理解 假設有這么一個表: CREATE TABLE `geek` ( 有以下經常使用的查詢語句 這里我們需要思考,ca與cb索引是否都是必要的? ? ? 索引 ca 的組織是先按c排序,再按a排序,同時記錄主鍵(b),根據最左前綴原則,實際上,ca索引的功能同c索引的功能是差不多的,因此可以得出ca索引不是必要的 ? ? 索引 cb 的組織是先按c排序,再按b排序,同時記錄主鍵(a),因此該索引需要保留 |
MySQL中索引是如何組織數據的存儲的
| 假如有如下數據表: 對于表中每一行數據,索引中包含了last_name、first_name、dob列的值,下圖展示了索引是如何組織數據存儲的。 可以看到,索引首先根據第一個字段來排列順序,當名字相同時,則根據第三個字段,即出生日期來排序,正是因為這個原因,才有了索引的“最左原則”。 |
普通索引和唯一索引,應該怎么選擇?
| 在介紹這兩者的區別之前,我們先來介紹change buffer: 什么是change buffer? ? ? 1. 如果數據頁在內存中(buffer pool中時)就直接更新 ? ? ? ? ? ?1、從磁盤讀入數據頁到內存(老版本的數據頁); ? ? ? ? ? ?2、從change buffer里找出這個數據頁的change buffer 記錄(可能有多個),依次應用,得到新版數據頁; ? ? ? ? ? ?3、寫redo log。這個redo log包含了數據的變更和change buffer的變更。 ? ? 而唯一索引的更新就不能使用 change buffer:對于唯一索引,所有的更新操作都要先判斷這個操作是否違反唯一性約束。那么必須將數據頁讀入內存才能判斷。比如,要插入(4,400) 這個記錄,就要先判斷現在表中是否已經存在 k=4 的記錄 ? ? 都已經讀入內存中了,那直接更新內存會更快,沒有必要使用change buffer了。 ? ? 所以,只有普通索引才能使用change buffer,考慮使用普通索引還是唯一索引,如果能保證不會數據重復,那么最好使用普通索引(可以使用change buffer,且兩類索引查詢能力沒有區別) 注意:不是所有的場景用change buffer都能加速: ? ? 1. 設想一個對于寫多讀少的業務來說,change buffer 記錄的變更越多越劃算,例如賬單類日志類 ? ? 2. 反過來,一個業務的更新模式是寫入之后馬上會做查詢,change buffer里的內容不多,由于馬上做查詢要訪問數據頁,這樣的io次數不會減少 如果某次寫入使用了change buffer機制,之后主機異常重啟,是否會丟失change buffer和數據? ? ? 雖然寫入時只更新了內存,但是在事務提交的時候,change buffer的操作也會記錄到redo log,所以崩潰恢復的時候,change buffer也能找回來,即數據可以找回來。 所以普通索引和唯一索引,應該怎么選擇? ? ? 查詢時:兩種索引查詢性能幾乎沒差別 ? ? 更新時:大部分場景下,因為有change buffer的存在,普通索引的更新速度會比唯一索引的快(特別適用于寫多讀少的場景)(如果所有的更新后面,都馬上伴隨著對這個記錄的查詢,那么應該關閉change buffer) |
擴展閱讀:
Mysql索引原理https://mp.weixin.qq.com/s/9yeModGuGvDu5S0bW9sU6w
Mysql是如何根據索引查詢數據的https://mp.weixin.qq.com/s/ymWeGlaBYWYmfogVDFHo5w
總結
以上是生活随笔為你收集整理的MySQL数据库索引的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 枪毙ctfmon.exe 恢复你的默认输
- 下一篇: Windows Server 2016安