這里想整理一下性能優化中用到的東西,先整理一下優化mysql索引中所查閱到的資料吧。
目錄
- MySQL索引類型詳解
- 存儲方式區分
- 1.B+樹索引
- 2.哈希索引
- 邏輯區分
- 1.普通索引
- 2. 唯一索引
- 3. 主鍵索引
- 4. 空間索引
- 5. 全文索引
- 實際使用區分
- 1. 單列索引
- 2. 多列索引
- 多表聯查如何建立索引
- 具體方法與建議
- 原則與建議
- 索引優化分析
- 盡量避免負向查詢
- 避免使用select *
- 避免創建冗余索引
- 如何防止你的索引失效
MySQL索引類型詳解
索引的類型和存儲引擎有關,每種存儲引擎所支持的索引類型不一定完全相同。MySQL 索引可以從存儲方式、邏輯角度和實際使用的角度來進行分類。
存儲方式區分
根據存儲方式的不同,MySQL 中常用的索引在物理上分為 B+樹索引和 HASH 索引兩類,兩種不同類型的索引各有其不同的適用范圍。
1.B+樹索引
B+樹索引又稱為 BTREE 索引,目前大部分的索引都是采用 B+樹索引來存儲的。
MySQL中,索引是在存儲引擎層實現的,不同的存儲引擎支持的索引類型不同,對索引的組織實現方式也不同。我們平時最常使用的是B+樹索引,B+樹是為磁盤或其他存取設備設計的一種平衡查找樹,所有記錄節點按照鍵值大小順序存放在同一層的葉節點上,各葉節點通過指針進行鏈接
B+樹索引是一個典型的數據結構,其包含的組件主要有以下幾個:
-
葉子節點:包含的條目直接指向表里的數據行。葉子節點之間彼此相連,一個葉子節點有一個指向下一個葉子節點的指針。
-
分支節點:包含的條目指向索引里其他的分支節點或者葉子節點。
-
根節點:一個 B+樹索引只有一個根節點,實際上就是位于樹的最頂端的分支節點。
基于這種樹形數據結構,表中的每一行都會在索引上有一個對應值。因此,在表中進行數據查詢時,可以根據索引值一步一步定位到數據所在的行。
其基本特征如下:
- 非葉節點只存關鍵字以及索引下一層節點的指針
- 所有葉節點在同一層,包含全部關鍵字和指向記錄的指針,并且按照關鍵字從小到大順序鏈接
可以看到相比一般二叉樹,B+樹的單個節點能存儲更多信息,減少了磁盤 IO 的次數,從而提升了查找速度,而且葉節點形成有序鏈表,非常適合進行范圍查詢。
B+樹索引可以進行全鍵值、鍵值范圍和鍵值前綴查詢,也可以對查詢結果進行 ORDER BY 排序。但 B+樹索引必須遵循左邊前綴原則,要考慮以下幾點約束:
查詢必須從索引的最左邊的列開始。
查詢不能跳過某一索引列,必須按照從左到右的順序進行匹配。
存儲引擎不能使用索引中范圍條件右邊的列。
2.哈希索引
哈希(Hash)一般翻譯為“散列”,也有直接音譯成“哈希”的,就是把任意長度的輸入(又叫作預映射,pre-image)通過散列算法變換成固定長度的輸出,該輸出就是散列值。
哈希索引也稱為散列索引或 HASH 索引。MySQL 目前僅有 MEMORY 存儲引擎和 HEAP 存儲引擎支持這類索引。其中,MEMORY 存儲引擎可以支持 B+樹索引和 HASH 索引,且將 HASH 當成默認索引。
HASH 索引不是基于樹形的數據結構查找數據,而是根據索引列對應的哈希值的方法獲取表的記錄行。哈希索引的最大特點是訪問速度快,但也存在下面的一些缺點:
- MySQL 需要讀取表中索引列的值來參與散列計算,散列計算是一個比較耗時的操作。也就是說,相對于 B+樹索引來說,建立哈希索引會耗費更多的時間。
- 不能使用 HASH 索引排序。
- HASH 索引只支持等值比較,如“=”“IN()”或“”。
- HASH 索引不支持鍵的部分匹配,因為在計算 HASH 值的時候是通過整個索引值來計算的。
邏輯區分
根據索引的具體用途,MySQL 中的索引在邏輯上分為以下 5 類:
1.普通索引
普通索引是 MySQL 中最基本的索引類型,它沒有任何限制,唯一任務就是加快系統對數據的訪問速度。
普通索引允許在定義索引的列中插入重復值和空值。
創建普通索引時,通常使用的關鍵字是 INDEX 或 KEY。
例 1
下面在 tb表中的 id 字段上建立名為 index_id 的索引。
CREATE INDEX index_id ON tb(id);
2. 唯一索引
唯一索引與普通索引類似,不同的是創建唯一性索引的目的不是為了提高訪問速度,而是為了避免數據出現重復。
唯一索引列的值必須唯一,允許有空值。如果是組合索引,則列值的組合必須唯一。
創建唯一索引通常使用 UNIQUE 關鍵字。
例 2
下面在 tb 表中的 id 字段上建立名為 index_id 的索引,SQL 語句如下:
CREATE UNIQUE INDEX index_id ON tb(id);
3. 主鍵索引
顧名思義,主鍵索引就是專門為主鍵字段創建的索引,也屬于索引的一種。
主鍵索引是一種特殊的唯一索引,不允許值重復或者值為空。
創建主鍵索引通常使用 PRIMARY KEY 關鍵字。不能使用 CREATE INDEX 語句創建主鍵索引。
4. 空間索引
空間索引是對空間數據類型的字段建立的索引,使用 SPATIAL 關鍵字進行擴展。
創建空間索引的列必須將其聲明為 NOT NULL,空間索引只能在存儲引擎為 MyISAM 的表中創建。
空間索引主要用于地理空間數據類型 GEOMETRY。對于初學者來說,這類索引很少會用到。
例 3
下面在 tb 表中的 line 字段上建立名為 index_line 的索引,SQL 語句如下:
CREATE SPATIAL INDEX index_line ON tb(line);
其中,tb 表的存儲引擎必須是 MyISAM,line 字段必須為空間數據類型,而且是非空的。
5. 全文索引
全文索引主要用來查找文本中的關鍵字,只能在 CHAR、VARCHAR 或 TEXT 類型的列上創建。在 MySQL 中只有 MyISAM 存儲引擎支持全文索引。
全文索引允許在索引列中插入重復值和空值。
不過對于大容量的數據表,生成全文索引非常消耗時間和硬盤空間。
創建全文索引使用 FULLTEXT 關鍵字。
例 4
在 tb 表中的 info 字段上建立名為 index_info 的全文索引,SQL 語句如下:
CREATE FULLTEXT INDEX index_info ON tb(info);
其中,index_info 的存儲引擎必須是 MyISAM,info 字段必須是 CHAR、VARCHAR 和 TEXT 等類型。
實際使用區分
索引在邏輯上分為以上 5 類,但在實際使用中,索引通常被創建成單列索引和組合索引。
1. 單列索引
單列索引就是索引只包含原表的一個列。在表中的單個字段上創建索引,單列索引只根據該字段進行索引。
單列索引可以是普通索引,也可以是唯一性索引,還可以是全文索引。只要保證該索引只對應一個字段即可。
例 5
下面在 tb 表中的 address 字段上建立名為 index_addr 的單列索引,address 字段的數據類型為 VARCHAR(20),索引的數據類型為 CHAR(5)。SQL 語句如下:
CREATE INDEX index_addr ON tb(address(5));
這樣,查詢時可以只查詢 address 字段的前 5 個字符,而不需要全部查詢。
2. 多列索引
組合索引也稱為復合索引或多列索引。相對于單列索引來說,組合索引是將原表的多個列共同組成一個索引。多列索引是在表的多個字段上創建一個索引。該索引指向創建時對應的多個字段,可以通過這幾個字段進行查詢。但是,只有查詢條件中使用了這些字段中第一個字段時,索引才會被使用。
例如,在表中的 id、name 和 sex 字段上建立一個多列索引,那么,只有查詢條件使用了 id 字段時,該索引才會被使用。
例 6
下面在 tb 表中的 name 和 address 字段上建立名為 index_na 的索引,SQL 語句如下:
CREATE INDEX index_na ON tb(name,address);
該索引創建好了以后,查詢條件中必須有 name 字段才能使用索引。
提示:一個表可以有多個單列索引,但這些索引不是組合索引。一個組合索引實質上為表的查詢提供了多個索引,以此來加快查詢速度。比如,在一個表中創建了一個組合索引(c1,c2,c3),在實際查詢中,系統用來實際加速的索引有三個:單個索引(c1)、雙列索引(c1,c2)和多列索引(c1,c2,c3)。
索引的優缺點主要體現在:
- 優勢:可以快速檢索,減少I/O次數,加快檢索速度;根據索引分組和排序,可以加快分組和排序;
- 劣勢:索引本身也是表,因此會占用存儲空間,一般來說,索引表占用的空間的數據表的1.5倍;索引表的維護和創建需要時間成本,這個成本隨著數據量增大而增大;構建索引會降低數據表的修改操作(刪除,添加,修改)的效率,因為在修改數據表的同時還需要修改索引表;
多表聯查如何建立索引
在 MySQL 數據庫中,設計索引主要是為了提高查詢的效率,降低數據庫的壓力。當我們進行多表查詢時,正確設計索引非常重要。
具體方法與建議
- 為連接列創建索引:在多表查詢中,連接列通常是性能瓶頸。為這些列創建索引可以顯著提高查詢性能。
- 考慮表的關聯順序:在JOIN語句中,表的順序可能會影響性能。通常,你應該從具有最小數量的唯一行的表開始,然后逐步添加其他表。
- 考慮使用覆蓋索引:如果查詢只涉及某些列,并且這些列在索引中包含了所有需要的值,那么可以使用覆蓋索引來提高性能。
- 考慮聯合索引:如果你有多個列在查詢中經常一起出現,那么可以考慮創建聯合索引。
- 不要過度索引:雖然索引可以提高性能,但是過多的索引也會增加存儲空間的開銷,并可能降低插入、更新和刪除操作的性能。因此,要平衡索引的使用。
原則與建議
-
理解數據和查詢:在設計索引之前,首先需要理解你的數據和查詢。知道哪些列經常被用于 WHERE,ORDER BY,GROUP BY 等子句,以及哪些列經常被 JOIN。這些列可能需要被索引。
-
單列索引:如果某一列經常被獨立用于搜索,那么可以為其創建單列索引。例如,如果經常在 user 表上通過 email 列進行搜索,那么可以為 email 列創建索引。
-
復合索引:如果有多個列經常一起被用于搜索,那么可以為這些列創建復合索引。復合索引中列的順序對性能有很大影響。在復索引中,索引的順序應該是:最常用于搜索條件的列(高選擇性)放在前面,不經常用于搜索條件的列(低選擇性)放在后面。
-
覆蓋索引:如果一個查詢可以通過使用一個索引獲取所有的信息,那么這個索引被稱為覆蓋索引。覆蓋索引可以大大提高查詢性能,因為 MySQL 可以只通過索引就獲取所有需要的信息,而無需回表。
-
利用索引合并:MySQL 可以在一次查詢中使用多個索引,這被稱為索引合并。索引合并可以優化復雜的查詢條件,但并不總是最佳選擇。如果可能,應該嘗試創建一個復合索引來替代索引合并。
-
避免全表掃描:設計索引的目的之一是避免全表掃描。全表掃描非常低效,應該盡量避免。
這些原則可以幫助你設計索引,但是具體的索引策略還需要根據你的具體情況進行調整。不同的數據、查詢和硬件可能需要不同的索引策略。
下面是一個具體的實驗步驟,可以參考進行操作:
- 創建測試數據庫和測試表,插入一些測試數據。
- 執行你的查詢,記錄查詢的時間和性能。
- 創建一些索引,然后再次執行你的查詢,比較查詢的時間和性能。
- 調整索引(例如,改變復合索引的列的順序,添加或刪除某些索引),然后再次執行你的查詢,比較查詢的時間和性能。
- 通過比較查詢的時間和性能,找出最佳的索引策略。
索引優化分析
可以通過索引來優化查詢語句的執行效率。MySQL 中,可以使用 EXPLAIN 命令來查看查詢語句的執行計劃,進而優化查詢。如果查詢語句沒有使用索引,可以考慮添加索引或者修改查詢語句的條件,使其能夠利用索引來加快查詢速度。
需要注意的是,雖然索引可以加快查詢速度,但是過多的索引也會影響數據庫的性能,因為索引需要占用存儲空間,并且在修改表數據時也會增加操作的復雜度。因此,在創建索引時需要根據實際情況進行選擇和權衡,避免過度使用索引。
索引的優化是非常必要的,因為索引可以極大地提高數據庫的查詢效率,特別是對于大量數據的表。在建立索引時,需要權衡利弊。一般來說,對于經常被查詢、查詢效率需要提高的列,可以建立索引;而對于不經常被查詢的列,或者存儲空間比較緊張的情況下,可以考慮不建立索引。同時,可以考慮對于一些查詢頻繁但數據更新較少的列建立索引,并定期進行索引維護來保證查詢效率。因此,正確的創建和使用索引是實現高性能查詢的基礎。
盡量避免負向查詢
負向查詢指的是在查詢中使用不等于(<>)或不包含(NOT IN、NOT EXISTS等)的條件,即查詢不滿足某些條件的記錄。負向查詢通常會導致數據庫執行全表掃描,影響查詢性能。
避免使用select *
查詢時盡量不要使用select *,而是只查出需要的字段,因為select * 無法利用覆蓋索引優化,還會為服務器帶來額外的IO、內存和cpu的消耗
避免創建冗余索引
在數據庫中,創建過多的索引會導致查詢性能下降、插入/更新/刪除操作變慢等問題,而創建冗余索引則是其中一種常見的問題。冗余索引指的是已經存在一條索引可以滿足查詢條件,但是又創建了另一條重復的索引。這種索引不僅浪費存儲空間,還會使得數據庫維護索引的代價更大,影響數據庫性能。
避免創建冗余索引的方法包括:
- 仔細分析查詢需求,只創建必要的索引。
- 定期檢查數據庫中的索引,及時刪除冗余的索引。
- 盡量避免創建覆蓋索引,因為它可能包含多個不必要的字段。
需要注意的是,索引的設計并不是一成不變的,需要根據具體的業務需求和數據特征不斷進行調整和優化。
如何防止你的索引失效
- 使用多列作為索引,需要遵循最左前綴匹配原則(查詢從索引的最左前列開始并且不跳過索引中的列)
- 不在索引列上做任何操作,例如:計算、函數、自動or手動的類型轉換,會導致索引失效而轉向全表掃描
如果你對列進行了(+,-,*,/,!)、函數、or運算,那么都將不會走索引 - 盡量使用索引覆蓋(只訪問索引列的查詢),減少select * ,覆蓋索引能減少回表次數
- mysql在使用不等于(!=或者<>)的時候無法使用索引會導致全表掃描
- like以通配符開頭(%abc),mysql索引會失效變成全表掃描的操作
- 字符串不加單引號會導致索引失效(可能發生了索引列的隱式轉換)
例如 select * from tb where name = name;