索引為什么能夠提高MySQL的查詢效率?
索引可以理解為目錄,通過索引可以快速定位數據,避免全表掃描
一般是B+樹結構,查找效率是O(log n)。
索引還能加速排序、分組、連接等操作。
create index idx_name on students(name);
能簡單說一下索引的分類嗎?
從功能上分,有主鍵索引、唯一索引、聯合索引、前綴索引和全文索引。
從數據結構上分,有B+樹索引、哈希索引。
從存儲內容上分,有聚簇索引、非聚簇索引。
你對主鍵索引了解多少?
主鍵索引用于唯一標識表中的每條記錄,其列值必須唯一且不為空。創建主鍵時會自動生成主鍵索引。
唯一索引和主鍵索引有什么區別?
主鍵索引 = 唯一索引 + 非空,每個表只能有一個主鍵索引,但是可以有多個唯一索引,唯一索引的列允許插入多個NULL值。
unique key和unique index有什么區別?
unique key是一種約束,創建唯一鍵時,MySQL會自動創建一個同名的唯一索引;反之,創建唯一索引也會隱式添加唯一性約束。
可通過 UNIQUE KEY uk_name 定義或者 CONSTRAINT uk_name UNIQUE 定義唯一鍵。
可通過 CREATE UNIQUE INDEX 創建唯一索引。
你對全文索引了解多少?
全文索引是一種優化文本數據檢索的特殊類型索引,適用于CHAR、VARCHAR、TEXT?
建表時可以通過FULLTEXT INDEX index_name (title, body) WITH PARSER ngram定義
ngram是一種解析器,可以處理中文日文韓文分詞
使用時用MATCH(title, content) AGAINST('+xxx -xxx' IN BOOLEAN MODE)
默認按降序返回結果,+標識必須包含,-表示必須排除,*表示通配符。
底層使用倒排索引將字段中的文本內容進行分詞,然后建立一個倒排表,不是從文檔找詞匯,而是從詞匯找文檔。
創建索引有哪些注意點?
第一、選擇合適的字段
- 比如說頻繁出現在 WHERE、JOIN、ORDER BY、GROUP BY 中的字段。
- 優先選擇區分度高的字段,比如用戶 ID、手機號等唯一值多的,而不是性別、狀態等區分度極低的字段,如果真的需要,可以考慮聯合索引。
第二、要控制索引的數量,避免過度索引,比如說已經有聯合索引 (a, b),單索引(a)就是冗余的。每個索引都要占據存儲空間,建議單表的索引不超過五個。
第三、聯合索引使用時遵循最左前綴原則,定義時區分度高的字段優先于區分度低的字段,等值查詢的字段優先于范圍查詢的字段。
索引哪些情況下會失效?
索引列使用了函數、使用了通配符開頭的模糊查詢、聯合索引不滿足最左前綴原則、WHERE條件中使用or的時候部分字段無索引等
索引不適合哪些場景呢?
區分度低的列、頻繁更新的列(列更新代表索引也要更新)、數據量小時
區分度 = 字段的唯一值數量 / 字段的總記錄數
索引是不是建的越多越好
不是,索引是會占用空間的,并且更新建了索引的字段的值也會同時更新索引,導致寫入變慢。在索引過多的情況下優化器也有可能選錯索引
說說索引優化的思路??
先通過慢查詢日志找出哪些SQL拖后腿,然后調用EXPLAIN查看執行計劃,看看是不是走了索引,是否回表、是否排序。然后根據字段特性設計合適的索引,如選擇區分度高的字段,使用聯合索引和覆蓋索引,避免索引失效的寫法,最后通過實測來驗證優化效果。
為什么innodb要使用B+樹作為索引?
降低磁盤的I/O次數,支持有序遍歷和范圍查找,因為索引本來就是有序的。
B+樹的每個節點都是一個頁,MySQL在磁盤中也是按頁存儲的。
B+樹的葉子節點構成了一個有序鏈表
哈希表不支持范圍查詢(無序),二叉樹太深,B樹所有節點都要存數據,所以使用B+樹
為什么MongoDB的索引采用B樹,而MySQL采用B+樹?
MongoDB通常以類似JSON形式存儲文檔,查詢的時候一般是使用單鍵等值。B樹既存儲key由存儲數據,這樣允許搜索的時候允許在非葉子節點提前終止,減少IO次數。
MySQL的查詢一般涉及范圍、排序、分組等操作。B+樹的葉子節點是雙向鏈表結構,無序回溯查找,直接通過葉子節點鏈表順序遍歷即可,天然具有有序性。
一顆B+樹能存多少條數據?
取決于樹的高度和分支因子
(分支因子)^(樹高度-1) × 葉子節點容量
對于 2KW 條數據來說,B+樹的高度為 3 層就夠了。
為什么索引用B+樹而不用二叉樹?
因為二叉樹在按照順序從大到小插入時會退化成鏈表,樹的高度就是數據量,導致IO次數增多。
平衡二叉樹雖然解決了退化成鏈表的問題,但是每個節點仍然只能有兩個分支,深度仍然很大。?
為什么使用B+樹而不是B樹?
第一,B 樹的每個節點既存儲鍵值,又存儲數據和指針,導致單節點存儲的鍵值數量較少。
第二、B 樹的范圍查詢需要通過中序遍歷逐層回溯;而 B+ 樹的葉子節點通過雙向鏈表順序連接,范圍查詢只需定位起始點后順序遍歷鏈表即可,沒有回溯開銷。
第三,B 樹的數據可能存儲在任意節點,假如目標數據恰好位于根節點或上層節點,查詢僅需 1-2 次 I/O;但如果數據位于底層節點,則需多次 I/O,導致查詢時間波動較大。
而 B+ 樹的所有數據都存儲在葉子節點,查詢路徑的長度是固定的,時間穩定為 O(logN),對 MySQL 在高并發場景下的穩定性至關重要。
為什么使用B+樹而不使用跳表?
跳表本質上仍然是鏈表,假設每次向下都是二分查找,那么2000w條數據下,查找需要24次IO,因為2000w≈2^24,而B+樹最多只需要三次IO就夠了
B+樹的范圍查找怎么做的?
先通過索引路徑定位到第一個滿足條件的葉子節點,然后順著葉子節點之間的鏈表向右/向左掃描,直到超過范圍。
了解快排嗎?
用分治法將一個序列分割為較小和較大的兩個子序列,然后遞歸排序兩個字序列。
核心思想是選擇一個基準值,將數組分為兩個部分,左邊小于基準值,右邊大于等于基準值
B+樹索引和哈希索引有什么區別?
B+樹索引是一種平衡多路搜索樹,所有的數據都存在葉子節點上,非葉子節點只存儲key和頁面指針,葉子節點是有序的,支持范圍查找和有序遍歷和模糊查詢。
Hash索引是將鍵值映射到固定長度的哈希值,通過哈希值定位數據的位置,不支持有序遍歷和范圍查找,完全無序,只支持等值查詢,常見于Memory引擎。
聚簇索引和非聚簇索引有什么區別?
聚簇索引的葉子節點不僅存儲索引,還存儲了完整行數據,數據和索引是一起的,InnoDB的主鍵索引就是聚簇索引。非聚簇索引的葉子節點存儲的是索引和對應聚簇索引的鍵值(主鍵值),需要回表。非主鍵索引都是非聚簇索引,比如唯一索引,普通索引,全文索引,前綴索引,聯合索引。
如果使用非主鍵索引也不想回表,可以定義覆蓋索引,并在使用的時候遵循左前綴原則。
回表了解嗎?
使用非聚簇索引時,索引沒有覆蓋所需要查找的列,需要通過非聚簇索引的葉子節點找到對應的主鍵值,再利用主鍵值在聚簇索引中找到完整的行記錄,這個過程稱為回表。
回表的代價是什么?
回表需要訪問額外的數據頁,如果想要訪問的數據不在內存中,還需要從磁盤查找,增加IO開銷
可以通過聯合索引和覆蓋索引避免回表?
什么情況下會觸發回表?
當查詢字段不在非聚簇索引的葉子節點的鍵值中時候,必須回到主鍵索引中獲取數據
查詢字段包含非索引列的時候,必然觸發回表
了解MRR嗎
MRR是為了避免大量回表引來的大量隨機IO問題引入的一種優化策略。
把非聚簇索引查到的主鍵值列表進行排序,再按順序去主鍵索引中批量回表,將隨機IO轉換為順序IO,減少磁盤尋道時間。
聯合索引了解嗎?
聯合索引就是把多個字段放在一個索引里,但必須遵守“最左前綴”原則,只有從第一個字段開始連續使用,索引才會生效。
聯合索引會根據字段的順序構造B+樹,比如定義了(age, name),會先根據age排序,age相同是再根據name排序,若兩者都相同則按照主鍵排序。
創建(A,B,C)
聯合索引相當于同時創建了(A)
、(A,B)
和(A,B,C)
三個索引。
聯合索引底層的存儲結構是什么樣的?
B+樹結構,每個節點都存儲了所有的索引列值作為key,并且按照定義時的順序排序。
非葉子節點存儲所有的索引列值,并且存儲了指向子節點的指針。
葉子節點存儲了所有索引列的值,并且存儲了對應的主鍵值。
什么是最左前綴原則?
在聯合索引中,必須從最左邊的字段開始匹配,才能命中索引
范圍查詢后的列還能用作索引嗎?
不能,范圍查詢會中斷后面列的索引使用,因為索引是根據左前綴組織的,只有當左前綴的列值相同時,當前列值才有序。范圍查詢后,后續的字段不再有序。
為什么不從最左邊開始查,就無法匹配呢?
因為聯合索引組織的時候就是按照最左邊的列進行排序的,最左邊的列相同后,再依次按照后面的列值進行排序。如果不從左邊開始查,無法判斷查找范圍。
什么是索引下推?
沒有ICP的情況下,先在數據引擎層用索引查出來記錄,WHERE過濾是在服務層進行。ICP,是指把WHERE條件盡可能下推到索引掃描階段,在存儲引擎層提前過濾掉不符合條件的記錄,這樣可以減少回表次數。