高性能MySQL--索引學習筆記(原創)

看過一些人寫的學習筆記,徹底按書一字不漏照抄,內容不少,真不能叫筆記。遂本身整理了一份,取其精要。
更多筆記請訪問@我的簡書sql

索引概述

  • 索引即key
  • 在存儲引擎層實現,不一樣引擎工做方式不一樣
  • 索引優化--最好的查詢優化手段,可提效幾個數量級緩存

  • 兩步查找數據:安全

    磁盤查找索引節點(頁),將其調入內存;
    內存內業內查找數據服務器

一. 索引類型

B-Tree
Hash
R-Tree空間數據索引
全文索引dom

1. B-tree索引

  • 支持引擎:InnoDB,MyISAM,Memory

  • 全部葉子值順序存儲,且到root高度同樣
  • InnoDB,MyISAM B-tree工做方式異同:ide

    InnoDB按原格式存儲數據,MYISAM用前綴壓縮技術
    InnoDB用主鍵key索引數據行,MyISAM用物理位置索引數據行函數

  • 加速:存儲引擎從root節點掃描,代替全表掃描
  • 葉節點指針-->被索引數據(data record)工具

1)B-Tree適用場景

1 全值匹配查詢

全部列都匹配性能

2 最左前綴匹配

組合索引第一列

3 列前綴匹配

某列值開頭

4 範圍值匹配
5 一列精確一列範圍匹配
6 覆蓋索引查詢

只訪問索引便可取data,無須訪問數據行

7 Order by排序

2) B-Tree不適用場景

  • 非最左列
  • 跳列

    A C

  • 某列進行範圍查詢,其右邊全部列沒法再用索引

2. Hash索引

  • 訪問哈希索引的數據很快

哈希表結構

f(key)=slot

1) 支持引擎

Memory,NDB集羣

2) 適用場景

索引全列匹配

3) 不適用場景

  • 不能從索引直接取data

    哈希索引=哈希值+行指針,不存儲字段值

  • 不能用於排序

    哈希值有序,但索引數據無序

  • 不支持部分索引列匹配
  • 不支持範圍查詢

    僅支持等值匹配 =,<=>,IN()

    <=> NULL安全等於----操做數可爲NULL

4) InnoDB自適應Hash索引

某些索引值被引用很頻繁,InnoDB自動在內存B-Tree索引上建立一個Hash索引
用戶沒法控制和配置,但可關閉

5) 自定義hash索引

存儲引擎不支持時,模擬建立hash

如何建立?

B-tree上建立僞hash索引

  • 仍在Btree上查找,但用hash索引值代替原Key(僞hash)
  • 須在where指定hash函數,不要用MD5(),SHA1()
select id from url
where url="www.mysql.com"
and
url_crc=CRC32("www.mysql.com")

其中urc_crc列爲索引列

6) 處理Hash衝突

使用hash索引查詢時,須在where指定常量

select id from url
where 
url_crc=CRC32("www.mysql.com")
and
url="www.mysql.com"
select word,crc from words
where 
crc=CRC32("gnu")
and
word="gnu"
@birthday problem

In probability theory, the birthday problem or birthday paradox concerns the
probability that,
in a set of {\displaystyle n} n randomly chosen people, some pair of them will have the same birthday.
By the pigeonhole principle, the probability reaches 100% when the number of people reaches 367 (since there are only 366 possible birthdays, including February 29). However, 99.9% probability is reached with just 70 people, and 50% probability with 23 people.

3. 空間數據索引 R-Tree

支持引擎:MyISAM
用做地理數據存儲,如美團,滴滴定位服務
任意維度組合查詢
須使用GIS函數維護數據,MySQL作的很差

4. 全文索引

  • 查找文本關鍵字,非比較索引鍵值
  • 相似搜索引擎
  • 相同列建立全文索引和B-Tree索引,不衝突

5. 其餘索引

第三方引擎TokuDB

二. 索引好處

1. 好處

1) 減小掃描數據量

2) 避免排序和臨時表

3) 隨機IO轉爲順序IO

2. 索引三星評價

評價索引是否適合某查詢
第一星

索引將相關data行放到一塊兒

第二星

索引的data行按查詢所需順序排序

第三星

索引含 查詢所有列

三 .高性能索引策略

1. 獨立的列

獨立

索引列非表達式子式,或函數參數

兩個錯誤:

1)索引列爲表達式
select id from actor
where id + 1 = 5
2)
select ...
where 
TO_DAYS(Current_DATE) - TO_DAYS(date_col) <= 10;

2. 前綴索引和索引選擇性

1) 前綴索引

很長字符串,可索引開始的部分字符串

適用場景

BLOB,TEXT,很長的VARCHAR列

2) 優缺點

優勢

節約索引空間

缺點

沒法使用之作order by,Group by
沒法使用作覆蓋索引

3) 索引選擇性

=不重複索引值/數據表記錄總數
  • 不重複索引值<-->基數<-->cardinality
  • 記錄總數<-->#T
  • 取值範圍 [1/#T ,1]
  • 越高越好

    選擇性越高,過濾掉的行越多

4) 如何找到 前綴索引長度

思想

足夠長(接近完整列),又不能太長(節約空間)

方法1 試驗法

先算完整列頻次,而後一個一個前綴試驗

計算完整列頻次

試驗前3前綴

方法2 計算完整列選擇性

使前綴選擇性接近完整列選擇性
完整列選擇性
前綴長度爲7接近完整列

5) 如何建立前綴索引

ALTER TABLE sakila
ADD KEY(city(7));

KEY(city(7))

3. 多列索引

1) 常見錯誤

每一個列都建立單獨索引,致使索引合併

create table t(
c1 int,
c2 int,
KEY(c1),
KEY(c2)
);

2) 索引合併表示索引建的很差,待優化

  • 多個索引相交(AND)不如組合索引好
  • 多個索引聯合(OR)耗費CPU和內存資源
  • 優化器不計算(耗費CPU和內存資源)到查詢成本中

4. 選擇合適的索引列順序

僅適用於BTree索引(按順序存儲數據)
Btree索引按從左到右順序,依次掃描
索引可按升、降序掃描,知足Order by,Group by,Distinct

如何選擇合適的索引列順序

經驗法則

無order by和Group by時,選擇性最高的列放在前面

select * from payment 
where staff_id=2 and customer_id=584;

key(staff_id,customer_id)仍是key(customer_id,staff_id)?

5. 聚簇索引(clustered index)

InnoDB支持,MyISAM爲非聚簇

聚簇

數據行,鍵值存儲在一塊兒
一個表只能有一個聚簇索引

聚簇特色

  • InnoDB經過主鍵彙集數據

    主鍵未定義,用惟一非空索引彙集
    無惟一非空索引,則隱式定義主鍵

  • 只彙集同一頁面記錄

聚簇優勢

  • 相關數據保存在一塊兒,如電子郵件(用戶ID和所有郵件)
  • 數據訪問更快(索引和數據都在BTree中)
  • 覆蓋索引查詢直接取頁節點鍵值

聚簇缺點

數據全放內存時無優點(訪問順序再也不重要)
插入速度依賴於插入順序

InnoDB按主鍵順序插入最快(不然插入後用optimize table優化表)

更新聚簇索引列代價很高

強制將每一個更新行移動到新位置

頁分裂問題

插入新行或,主鍵更新致使需移動行時

全表掃描慢
二級索引需兩次索引查找

二級索引(secondary index,輔助索引)

葉節點保存行主鍵值,非指向data行的物理記錄的指針

二級索引查找行步驟
  1. 葉子節點找到主鍵值
  2. 在聚簇索引找數據行

1 . InnoDB和MyISAM數據分佈對比

InnoDB數據分佈


InnoDB就是表,不用再像Myisam用單獨列存儲
聚簇索引葉子節點包含:
主鍵值
事物ID
回滾指針(用於事物和MVCC)
其餘剩餘列

聚簇和非聚簇表對比

2. InnoDB表按主鍵順序插入行

無數據彙集,使用AUTO INCREMENT做爲主鍵--保證按順序寫入
避免使用UUID(universal unique identifier)聚簇索引--致使插入變得隨機

6. 覆蓋索引

索引直接包含所需查詢數據行,不須要回記錄表(數據表)
只能用BTree作覆蓋索引
支持InnoDB,myisam
Explain顯示 Extra:Using index

覆蓋索引優勢

  • 索引條目小於數據行,減小了數據訪問量
  • 範圍查詢IO少(索引列值順序存儲)
  • 對InnoDB表(聚簇索引)特別有用

    二級主鍵能覆蓋查詢可避免對主鍵索引的二次查詢

MyISAM覆蓋索引可能會致使系統問題

MyISAM引擎內存只緩存索引,數據由OS緩存

ICP索引條件推送(index condition pushdown)

MySQL5.6開始支持
條件過濾推到存儲引擎層完成,減小IO訪問

7. 用索引掃描作排序

MySQL生成有序結果的兩種方式

  • 排序
  • 按順序掃描索引

Exlain Type:Using index

爲什麼索引掃描比全表掃描慢?

若是索引不能覆蓋查詢所有列,則每掃一條索引記錄必須回表(隨機IO)

同一索引,既知足排序,又知足查找是最好的

什麼時候能用索引進行排序?

  • 索引列序和order by順序一致時
  • 且全部列排序方向同樣

不能使用索引進行排序的場景

  • order by出現不一樣排序方向
  • order by引用非索引列
  • where和order by中的列沒法組合爲最左前綴
  • where第一列是範圍條件
  • where出現IN(多個相等條件視爲範圍)

8. 壓縮(前綴壓縮)索引

MyISAM使用
減小索引大小(1/10磁盤空間)讓更多索引進入內存
默認只壓縮字符串,也可設置整數
只能從頭開始掃描,沒法二分
隨機掃描致使適用於IO密集型(OLTP),不適用CPU密集型(OLAP)?

index1:perform
index2:performance-->7,ance

9. 冗餘和重複索引

應刪除重複索引

1) 重複索引

相同列建立多個索引

三個重複索引--unique,primary限制均經過索引實現

2) 冗餘索引

應該刪除冗餘索引

兩種冗餘

已有key(A,B),再建key(A)
ID爲主鍵,擴展索引爲(A,ID)

建議

儘可能擴展示有索引,而不是建立新索引,那樣會致使冗餘索引

10.刪除未使用的索引

percona Toolkit--
pt-index-usage工具

11. 索引和鎖

InnoDB存儲引擎層完成條件過濾時(ICP--MySQL 5.6及之後),索引可減小訪問行數,從而減小加鎖數量
不然全表掃描並鎖住全部行

覆蓋索引失效:

  • InnoDB二級索引上用共享(讀)鎖,訪問主鍵索引須要排他(寫)鎖
  • select for update比lock in share mode或非鎖定查詢慢

四. 索引和表維護

維護表三目的

找到並修復損壞的表
維護準確的索引統計信息
減小碎片

1. 找到並修復表

1) MyISAM表

check table--檢查表
repair table--修復損壞的表

2) InnoDB表使用no-op ALTER

Alter TABLE innodb_tb ENGINE=INNODB;

2. 維護索引統計信息

優化器有時用索引統計信息估算掃描行數

ANALYZE TABLE更新統計信息避免錯誤

memory引擎不存儲統計信息
MyISAM引擎存儲統計信息在磁盤

Show Index from table查看索引基數(cardinality,索引列不一樣取值個數)

觸發索引統計信息更新的三種情形

SHOW TABLE STATUS
SHOW INDEX
打開某些INFORMATION_SCHEMA表

3.減小索引和數據碎片

1)BTree索引會碎片化,下降查詢效率

BTree隨機訪問是必須的,由於從root節點隨機磁盤訪問才能定位到葉子節點

2)三種數據碎片

行碎片

數據行存儲在多個地方多個碎片中

行間碎片

邏輯上順序的頁或行,在磁盤上非順序存儲

剩餘空間碎片

數據頁中有大量不用的空餘空間

MyISAM三種碎片都有,InnoDB無小碎片

3)如何消除碎片?

  • OPTIMIZE TABLE
  • ALTER TABLE tb ENGINE= ;
  • 刪除全部索引-->重建表 -->重建索引

五. 總結

索引三原則

1.單行訪問很慢

最好一個數據塊讀取多行

2. 按順序訪問範圍行很快

  • 順序IO無需屢次磁盤尋道,比隨機IO快不少
  • 服務器按順序讀取數據,則不須要額外排序

3. 索引覆蓋查詢很快

避免了大量單行訪問

相關文章
相關標籤/搜索