MySQL優化中,最重要的優化手段就是索引,也是最常用的優化手段 索引簡介: 索引:關鍵字與數據位置之間的映射關係 關鍵字:從數據中提取,用於標識,檢索數據的特定內容 目的:加快檢索 索引檢索為什麼快: (1)關鍵字相對於數據本身,量較小 (2)關鍵字都是排序好的 MySQL中索引的類型: 普通索引 ...
MySQL優化中,最重要的優化手段就是索引,也是最常用的優化手段
索引簡介:
索引:關鍵字與數據位置之間的映射關係
關鍵字:從數據中提取,用於標識,檢索數據的特定內容
目的:加快檢索
索引檢索為什麼快:
(1)關鍵字相對於數據本身,量較小
(2)關鍵字都是排序好的
MySQL中索引的類型:
普通索引,唯一索引,主鍵索引,全文索引
不同的類型只是對關鍵字的限制不同
普通索引:多索引關鍵字沒限制,有長度限制
唯一索引:要求記錄提供的關鍵字不能重覆
主鍵索引:要求關鍵字不能重覆而且不能為NULL
全文索引:不支持中文,後續細講
索引的語法:
查看索引:
SHOW CREATE TABLE [table-name];
比如查到PRIMARY KEY(‘id’),就是一個主鍵索引
創建索引:需要修改表結構和創建表時候完成,基於不同的類型,方式也不同
同時創建四個索引,由於使用到了全文索引,這裡使用MYISAM引擎
CREATE TABLE USER( ID INT AUTO_INCREMENT PRIMARY KEY, FIRST_NAME VARCHAR(16), LAST_NAME VARCHAR(16), SN VARCHAR(16), INFORMATION TEXT, KEY(FIRST_NAME,LAST_NAME), UNIQUE KEY(SN), FULLTEXT KEY(INFORMATION) )ENGINE=MYISAM;
索引可以命名,比如KEY NAME (FIRST_NAME,LAST_NAME)
這句話創建了一個基於FIRST_NAME和LAST_NAME的複合普通索引
UNIQUE KEY(SN) 創建了基於SN的唯一索引,預設以欄位名命名索引
最後一個全文索引很雞肋,基本不會用
在修改表結構的時候創建索引:
ALTER TABLE USER( ADD KEY(FIRST_NAME,LAST_NAME), ADD UNIQUE KEY(SN), ADD FULLTEXT KEY(INFORMATION) )
刪除索引:
ALTER TABLE [table-name] DROP PRIMARY KEY; ALTER TABLE [table-name] DROP KEY [key-name];
一般不簡易刪除主鍵索引,記錄是按照主鍵來排序的,設計主鍵要註意一定與業務邏輯無關
執行計劃:
執行計劃:當MySQL執行SQL語句時,會分析、優化、形成執行計劃後按照執行計劃來執行
在執行計劃中可以清楚的看到當前的查詢是否需要用到索引:
EXPLAIN SELECT * FROM [table-name] WHERE ID<20;
結果中有一樣:KEY:PRIMARY,代表該查詢語句會用到主鍵索引
索引使用的場景:
如果兩張表,學生和班級表,多對一的關係,導入較多的記錄來測試
(1)WHERE查詢
EXPLAIN SELECT * FROM STUDENT WHERE ID=123456
和上面的例子一樣,可以看到使用到了主鍵索引
EXPLAIN SELECT * FROM STUDENT WHERE USERNAME="XXX"
這句話執行後會發現:KEY:NULL,沒有索引
我們給它加上索引:(這裡的INDEX和上文的KEY都可以)
ALTER TABLE STUDENT ADD INDEX (USERNAME);
查看執行計劃後可以發現:KEY:USERNAME,說明使用到了新建的索引
(2)ORDER BY排序
我們有可能會遇到以下的情況:
SELECT * FROM STUDENT ORDER BY USERNAME;
查看執行計劃後可以發現沒有使用到任何索引,並且看到了Extra:Using Filesort,使用到了外部文件排序,性能更低,需要先將數據讀取到記憶體,分段讀取合併排序
提高效率的方式是增加索引:
ALTER TABLE STUDENT ADD INDEX (USERNAME);
現在查看執行計劃後,可以發現使用到了USERNAME索引,並且沒有使用外部文件排序,性能會有明顯提升
(3)JOIN 連接
使用到這條語句:
SELECT C.* COUNT(S.ID) FROM CLASS C JOIN STUDENT S ON C.ID=S.CLASS_ID GROUP BY C.ID;
當數據量巨大的時候,這句話要執行5S以上
查看執行計劃後,發現其中一張表沒有索引,且使用到了外部文件排序
解決:
ALTER TABLE STUDENT ADD INDEX (CLASS_ID);
執行後發現速度明顯提升,並且兩張表都使用到了索引,沒有外部文件排序
(4)索引覆蓋
前三條很重要,是必須做的優化,這條只是一個現象
比如我們使用這條語句:建立一個複合索引
ALTER TABLE STUDENT ADD INDEX (FIRSTNAME,LASTNAME);
然後再執行:這句話沒有使用到以上三種情況
SELECT FIRSTNAME,LASTNAME FROM STUDENT;
但是查看計劃後,發現還是使用到了索引,並且Extra:Using index,說明這句話只使用了索引來完成
如果執行這句話
SELECT FIRSTNAME,LASTNAME,USER FROM STUDENT;
再查看計劃後發現沒有使用到了索引,並且進行了全表掃描
兩次的差異只是多了一個USER欄位,而複合索引沒有包含該欄位
總結:MySQL的查詢優先使用了索引,由於索引覆蓋,建議SELECT後面只寫有必要的欄位,被覆蓋的可能性就會提升,儘可能地優化
語法註意細節:
(1)欄位需要獨立出現
SELECT * FROM STUDENT WHERE ID+1=20;
這句話是能執行成功的,ID是主鍵,查看計劃後卻沒有使用到主鍵索引
欄位沒有獨立出現,不能觸發該欄位上的索引,避免這種情況
(2)LIKE查詢不能以通配符開頭
SELECT * FROM STUDENT WHERE USERNAME LIKE '%A%';
這句話無法使用到索引,如果是以下的情況,那麼會用到索引
SELECT * FROM STUDENT WHERE USERNAME LIKE 'A%';
字元串比較中,不能使用包含的邏輯,比如查詢包含Java的字元串,不能寫'%Java%',效率過低
解決辦法:全文索引,但是MySQL全文索引很雞肋,應該使用第三方的比如ES,Solr
(3)複合索引的右側欄位不能獨立使用索引
已有INDEX NAME(FIRSTNAME,LASTNAME);
使用語句,這句話使用到了索引
SELECT * FROM STUDENT WHERE FIRSTNAME='XXX';
而下麵這句話沒有使用到索引
SELECT * FROM STUDENT WHERE LASTNAME='XXX';
原因:複合索引是按照左側欄位排序的,如果左側欄位相同再用右側欄位排序,總體上來看,右側欄位是未排序的
既然這樣為什麼還要建複合索引呢?以下這種情況
SELECT * FROM STUDENT WHERE FIRSTNAME LIKE 'XX%' AND LASTNAME LIKE 'XX%';
這句話如果建立兩個索引,那麼計算兩個索引的交集會更慢,所以需要複合索引
如果遇到上面的情況,再給LASTNAME建立一個索引即可
(4)早期版本NULL值無法使用索引
SELECT * FROM STUDENT WHERE FIRSTNAME=NULL;
新版本無需關心這一條
(5)OR語法保證兩邊的條件都有索引可用
SELECT * FROM STUDENT WHERE FIRSTNAME LIKE 'XX%' OR USER LIKE 'XX%';
如果USER沒有索引,那麼還是會全表查詢
(6)狀態值不容易使用到索引
GENDER 0,1,2表示男,女,未知
即使在欄位上增加了索引,通常也不會起作用
SELECT * FROM STUDENT WHERE GENDER IN (0,1);
原因:狀態值往往導致一個狀態值匹配大量記錄,查詢大量記錄的時候,MYSQL認為使用索引開銷比全表掃描都要大
如何創建索引:
(1)WHERE,ORDER BY,JOIN欄位上建立索引
(2)組合索引的建立:基於業務邏輯
(3)如果條件經常出現在一起,多欄位索引可以升級為複合索引
(4)如果通過增加個別欄位,就可以出現索引覆蓋,那麼增加個別欄位
(5)不會用到的索引應該刪掉
(6)常規情況下我們建立的資料庫系統本身性能就不差了
(7)有些欄位是否只使用首碼就能完成,使用首碼索引
首碼索引:INDEX(FIELD(10))
使用欄位field的前10個字元建立索引,預設是使用欄位全部內容建立索引
使用:GIT的COMMIT_ID;密碼欄位
索引的存儲結構:
BTREE索引,HASH索引,聚簇索引
以上概念指的是索引的存儲結構,數據結構上的概念,實際使用無需關心,瞭解即可
BTREE索引:
索引存儲在磁碟上所用的基礎的通用的存儲結構
特征:磁碟上的數據結構,不是二叉樹,一定要一個中文,那就是多路平衡查找樹
特點:一個BTREE節點,存儲多個索引關鍵字,多少由節點大小和關鍵字來確定的,
節點大小是固定的,由電腦文件系統來確定,一次性磁碟讀取記憶體量,就是一個節點大小
由於一個節點的大小是固定的,一個節點無法容納大量關鍵字,所以分散在多個節點來存儲關鍵字
這時候如何進行排序呢?通過上層節點的子節點指針指向下層節點,用來關聯所有的節點,子節點指針位於關鍵字之間
例如每個節點存儲1000個關鍵字,深度為2的兩層BTREE大概可以存儲1000000(1000*1000)個關鍵字
查找一個關鍵字,需要讀取幾個節點的內容呢?從根開始,確定下級節點,僅僅兩次的磁碟讀取就可以做到
Btree的意義在於可以遍歷大量關鍵字,減少磁碟讀取量的開銷
聚簇索引:
關鍵字和記錄在一起進行存儲
是升級後的Btree,數據結構上的B+Tree
MySQL中只有Innodb的主鍵索引是聚簇結構
HASH索引:
當索引被載入到記憶體後採用的存儲結構,採用哈希結構存儲了,類似Java的Map,Key-Value