爲何索引這麼快,一個好的索引能將檢索速度提高几個量級,這種效率離不開這個數據結構node
爲何須要"索引" ?
咱們總得依據什麼才能去找你想查的東西,那麼咱們就依據 id=1去尋找一條記錄,怎麼找呢? 難道是"順序檢索" ? sql
數據庫裏的東西如今大都大到分佈在不少個磁盤頁上。若是順序檢索基本就是噩夢。你知道"二分法" 比較快,那是由於數據已經被排過序了。 一樣的若是如今存在一種排過序的數據結構,使得咱們能快速去找出咱們想要的東西在哪兒,這樣必定很方便對吧。數據庫
因此歸根到底,如今最大的問題的就是"這條記錄到底存在哪"。 解決辦法是這樣的:爲何叫它"索引" ?
在上面的介紹中咱們已經看到了,實現快速找到內容的關鍵就是這個 "序號" 。這個所謂的序號就很是像"索引"這個名詞bash
爲何不用二分法查找?
理論上,二分法已是 O(logN), 很是快了。 實際上索引可能不少,多到你都沒辦法把索引所有加載到內存裏,因此這些索引基本上都在磁盤裏,依靠磁盤IO,分批次加載到內存裏。數據結構
既然提到磁盤IO,就應該知道磁盤IO效率很是低,低到實際上就,若是誰能減小磁盤IO次數,誰就會是最好的索引實現方案。優化
1.2.1 Balance-Tree中的節點爲何是這樣子 ? 查詢數據的過程ui
剛剛,咱們就走完了一個節點,咱們完成了一輪查找。每一輪開始以前咱們會先執行磁盤IO,把下一個節點對應內容從磁盤加載到內存裏,而後再在組內查找,找獲得就退出,找不到繼續spa
根據上述結論,咱們也能發現一個重要結論: 既然咱們不能一次性把全部索引都加載到內存裏,既然咱們要分批次作磁盤IO。那樹的高度其實就是咱們IO的次數,那麼矮樹就會是最快的方案3d
func balance_tree_search (node *Node , key int) (*Data,error) {
if node == nil {
return nil,fmt.Errorf("最終也沒能找到對應序號")
}
for _, pair := range node {
if (pair.Key == key){
return pair.Data,nil
}
if (pair.Key > key) {
// 考慮到節點內鍵值對是已經排序,從小到大的
// 那既然上個鍵值對不知足,這個鍵值對又過於大
// 那說明沒有符合的,前往下一個節點
return balance_tree_search( pair.NextNode, key )
}
}
// 比節點內全部鍵值對都大,直接前往下一個
return balance_tree_search( pair.NextNode, key )
}
複製代碼
1.2.2 Balance-Tree的插入過程指針
自調整的過程雖然很漫長,看起來也很麻煩,可是這個剛好是知足了BT的自調整性質
1.2.3 Balance-Tree的刪除過程
1.2.4 Balance-Tree的定義
假設咱們定義出A+B+C做爲索引列,哈希索引就是針對每一條記錄計算出hash(A,B,C) 對應的值是這條記錄存儲的位置,哈希索引很是快,可是也有自身對應的一些弊端
2.2.1 哈希衝突
假設如今兩條記錄能哈希出同一個值,這種時候:
// 若是隻依賴hash 則返回兩條記錄
SELECT * FROM users WHERE hash(name) = 1;
>> liangxiaohan 23 M
zhangxiaoming 24 F
// 最好的辦法是不只使用hash同時也指定索引列自身的值
// hash衝突下,造成鏈表,存儲引擎遍歷鏈表全部行
SELECT * FROM users WHERE hash(name) = 1 and name = "liangxiaohan"
>> liangxiaohan 23 M
複製代碼
2.2.2 自創索引
InnoDB支持哈希,但他的支持是指,它會自優化你的B樹索引成爲"某種程度上的"哈希索引。針對這一點,你能夠本身實現一個簡單的哈希索引
// 更新表,新建一列用於存放哈希值
ALTER TABLE ADD COLUMN name_crc VARCHAR(20)
// 關於哈希值,你可使用 TRIGGER 實現自動插入
// 你只負責插入name就好了,關於crc32哈希值它每次會本身計算
CREATE TRIGGER crc_create BEFORE INSERT ON users
FOR EACH ROW SET NEW.name_crc = crc32(NEW.name)複製代碼
2.3.1 關於聚簇索引,你須要知道
2.3.2 聚簇索引的優勢 & 缺點
背景: 獲取主頁面, 查詢前10條記錄,耗時2~3秒, 被描述爲" 不可忍受"的時間
1.1 咱們目前使用了那些數據庫索引?
MySQL[user] > SHOW INDEX FROM jobs;
*************************** 1. row ***************************
Table: jobs
Non_unique: 0
Key_name: PRIMARY <主鍵索引>
Seq_in_index: 1
Column_name: id
Collation: A
Cardinality: 13701
Sub_part: NULL
Packed: NULL
Null:
Index_type: BTREE
*************************** 2. row ***************************
Table: jobs
Non_unique: 1
Key_name: userId <惟一索引>
Seq_in_index: 1
Column_name: user_id
Collation: A
Cardinality: 105
Sub_part: NULL
Packed: NULL
Null: YES
Index_type: BTREE複製代碼
1.2 目前語句的查詢狀況是怎樣的?
MySQL [compile]>
EXPLAIN SELECT COUNT(j.id)
FROM
(SELECT * FROM jobs WHERE user_id = 123 AND deleted_at is NULL) j
LEFT JOIN
(SELECT * FROM builds WHERE deleted_at is NULL) b
ON
b.id = j.latest_build_id \G
*************************** 1. row ***************************
id: 1
select_type: PRIMARY
table: <derived2>
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 2
Extra: NULL
*************************** 2. row ***************************
id: 1
select_type: PRIMARY
table: <derived3>
type: ref
possible_keys: <auto_key0>
key: <auto_key0>
key_len: 4
ref: j.latest_build_id
rows: 1187
Extra: NULL
*************************** 3. row ***************************
id: 3
select_type: DERIVED -- 內嵌表
table: builds -- 表名
type: ALL -- 全表掃描,效率 ALL < index < range < ref < const
possible_keys: NULL -- 可能用到的索引
key: NULL -- 實際用到的索引
key_len: NULL
ref: NULL
rows: 118713 -- 預期掃描行數
Extra: Using where -- 使用Where作過濾,效率 filesort < temp < where < index
*************************** 4. row ***************************
id: 2
select_type: DERIVED
table: jobs
type: ref
possible_keys: userId
key: userId
key_len: 5
ref: const
rows: 1
Extra: Using where
MySQL [compile]> SELECT COUNT(j.id) FROM (SELECT * FROM jobs WHERE user_id = 4 AND deleted_at is NULL) j LEFT JOIN (SELECT * FROM builds WHERE deleted_at is NULL) b ON b.id = j.latest_build_id;
+-------------+
| COUNT(j.id) |
+-------------+
| 1280 |
+-------------+
1 row in set (0.93 sec)
複製代碼
1.3 查詢成本估計解讀