一 , 邏輯分層
連接層:連接與線程處理,這一層並不是MySQL獨有,一般的基於C/S架構的都有類似組件,比如連接處理、授權認證、安全等。
服務層:包括緩存查詢、解析器、優化器,這一部分是MySQL核心功能,包括解析、優化SQL語句,查詢緩存目錄,內置函數(日期、時間、加密等函數)的實現。
引擎層:負責數據存儲,存儲引擎的不同,存儲方式、數據格式、提取方式等都不相同,這一部分也是很大影響數據存儲與提取的性能的;對存儲層的抽象。
存儲層:存儲數據,文件系統。
二 , 存儲引擎
查看數據庫支持的存儲引擎:show engines;
如果要想查看數據庫默認使用哪個引擎,可以通過使用命令: show variables like '%storage_engine%';
指定數據庫對象的引擎:
create table tb(
id int(4) auto_increment ,
name varchar(5),
dept varchar(5) ,
primary key(id)
)ENGINE=MyISAM AUTO_INCREMENT=1
DEFAULT CHARSET=utf8 ;
查看建表語句:show create table default_table;
InnoDB,MyISAM的主要區別:
InnoDB:在MySQL5.5開始作為默認的存儲引擎,支持事務,行級鎖,適合高並發場景,XA協議支持分布式事務。
MyISAM:不支持事務,性能優先,表級鎖,不適合高並發場景。
三, sql優化
3.1.1 mysql 內部實現索引原理(B+Tree) 參考
https://blog.csdn.net/chuixue24/article/details/80027689
3.1.1.1 , 二叉樹
3.1.1.2 , B-Tree
一棵m階的B-Tree有如下特性:
1. 每個節點最多有m個孩子。
2. 除了根節點和葉子節點外,其它每個節點至少有Ceil(m/2)個孩子。
3. 若根節點不是葉子節點,則至少有2個孩子
4. 所有葉子節點都在同一層,且不包含其它關鍵字信息
5. 每個非終端節點包含n個關鍵字信息(P0,P1,…Pn, k1,…kn)
6. 關鍵字的個數n滿足:ceil(m/2)-1 <= n <= m-1
7. ki(i=1,…n)為關鍵字,且關鍵字升序排序。
8. Pi(i=1,…n)為指向子樹根節點的指針。P(i-1)指向的子樹的所有節點關鍵字均小於ki,但都大於k(i-1)
B-Tree中的每個節點根據實際情況可以包含大量的關鍵字信息和分支,如下圖所示為一個3階的B-Tree:
每個節點占用一個盤塊的磁盤空間,一個節點上有兩個升序排序的關鍵字和三個指向子樹根節點的指針,指針存儲的是子節點所在磁盤塊的地址。兩個關鍵詞划分成的三個范圍域對應三個指針指向的子樹的數據的范圍域。以根節點為例,關鍵字為17和35,P1指針指向的子樹的數據范圍為小於17,P2指針指向的子樹的數據范圍為17~35,P3指針指向的子樹的數據范圍為大於35。
模擬查找關鍵字29的過程:
-
-
- 根據根節點找到磁盤塊1,讀入內存。【磁盤I/O操作第1次】
- 比較關鍵字29在區間(17,35),找到磁盤塊1的指針P2。
- 根據P2指針找到磁盤塊3,讀入內存。【磁盤I/O操作第2次】
- 比較關鍵字29在區間(26,30),找到磁盤塊3的指針P2。
- 根據P2指針找到磁盤塊8,讀入內存。【磁盤I/O操作第3次】
- 在磁盤塊8中的關鍵字列表中找到關鍵字29。
-
分析上面過程,發現需要3次磁盤I/O操作,和3次內存查找操作。由於內存中的關鍵字是一個有序表結構,可以利用二分法查找提高效率。而3次磁盤I/O操作是影響整個B-Tree查找效率的決定因素。
B-Tree相對於AVLTree縮減了節點個數,使每次磁盤I/O取到內存的數據都發揮了作用,從而提高了查詢效率。
3.1.1.3 , B+Tree(查詢任意數據的次數是 n)
B+Tree是在B-Tree基礎上的一種優化,使其更適合實現外存儲索引結構,InnoDB存儲引擎就是用B+Tree實現其索引結構。
從上一節中的B-Tree結構圖中可以看到每個節點中不僅包含數據的key值,還有data值。而每一個頁的存儲空間是有限的,如果data數據較大時將會導致每個節點(即一個頁)能存儲的key的數量很小,當存儲的數據量很大時同樣會導致B-Tree的深度較大,增大查詢時的磁盤I/O次數,進而影響查詢效率。在B+Tree中,所有數據記錄節點都是按照鍵值大小順序存放在同一層的葉子節點上,而非葉子節點上只存儲key值信息,這樣可以大大加大每個節點存儲的key值數量,降低B+Tree的高度。
B+Tree相對於B-Tree有幾點不同:
- 非葉子節點只存儲鍵值信息。
- 所有葉子節點之間都有一個鏈指針。
- 數據記錄都存放在葉子節點中。
將上一節中的B-Tree優化,由於B+Tree的非葉子節點只存儲鍵值信息,假設每個磁盤塊能存儲4個鍵值及指針信息,則變成B+Tree后其結構如下圖所示:
通常在B+Tree上有兩個頭指針,一個指向根節點,另一個指向關鍵字最小的葉子節點,而且所有葉子節點(即數據節點)之間是一種鏈式環結構。因此可以對B+Tree進行兩種查找運算:一種是對於主鍵的范圍查找和分頁查找,另一種是從根節點開始,進行隨機查找。
可能上面例子中只有22條數據記錄,看不出B+Tree的優點,下面做一個推算:
InnoDB存儲引擎中頁的大小為16KB,一般表的主鍵類型為INT(占用4個字節)或BIGINT(占用8個字節),指針類型也一般為4或8個字節,也就是說一個頁(B+Tree中的一個節點)中大概存儲16KB/(8B+8B)=1K個鍵值(因為是估值,為方便計算,這里的K取值為〖10〗^3)。也就是說一個深度為3的B+Tree索引可以維護10^3 * 10^3 * 10^3 = 10億 條記錄。
實際情況中每個節點可能不能填充滿,因此在數據庫中,B+Tree的高度一般都在2~4層。mysql的InnoDB存儲引擎在設計時是將根節點常駐內存的,也就是說查找某一鍵值的行記錄時最多只需要1~3次磁盤I/O操作。
上面都應該知道B+Tree 了吧,所以我們在建立索引時,會生成一個B+Tree 如果我們在只查詢索引字段時,sql 語句就直接去B+Tree 查,不會再去數據表中查了,這樣提升性能是很重要的。 還有就是對於總是修改的字段不要對他建立索引,因為字段修改了,B+Tree 結構就要重構,這要是會降低性能的。
3.1.1 索引分類:
主鍵索引:是一種特殊的唯一索引,一個表只能有一個主鍵,不允許有空值。一般是在建表的時候某一列定為主鍵時,就默認的創建了對應的主鍵索引。
唯一索引:索引列的值必須唯一,但允許有空值。
單列索引:對於表中的某一列,添加的索引。
復合索引:多個列構成的索引(跟書的一級,二級,三級 目錄一樣),使用時要遵循最佳左前綴特性,如果我們創建了(area, age, salary)的復合索引,那么其實相當於創建了(area,age,salary)、(area,age)、(area)三個索引。
因此我們在創建復合索引時應該將最常用作限制條件的列放在最左邊,依次遞減。
3.2.2 如何正確的建立索引呢?
3.2.2、創建索引
create 索引類型 索引名 on 表(字段)
單值: create index dept_index on tb(dept);
唯一:create unique index name_index on tb(name) ;
復合索引: create index dept_name_index on tb(dept,name);
查詢索引:
show index from 表名 ;
show index from 表名 \G
刪除索引:
drop index 索引名 on 表名 ;
drop index name_index on tb ;
然而它的執行順序是這樣的
FROM ..... ON ..... JOIN ..... WHERE ..... GROUP BY ..... HAVING ..... SELECT DISTINCT ..... ORDER BY ..... LIMIT .....
一般說來,索引應建立在那些將用於JOIN,WHERE判斷和ORDERBY排序的字段上。盡量不要對數據庫中某個含有大量重復的值的字段建立索引。對於一個ENUM類型的字段來說,出現大量重復值是很有可能的情況.
3.2.4 使用索引時,有一些技巧:
1.索引不會包含有NULL的列
只要列中包含有NULL值,都將不會被包含在索引中,復合索引中只要有一列含有NULL值,那么這一列對於此符合索引就是無效的。
2. 索引要建立在經常進行select操作的字段上。而經常修改的字段,沒沒必要建立索引了,因為,你建立了索引會生成一個B+樹,你修改了該索引的字段后,這個B+樹就需要修改,反而對性能不是很好。
3. 復合索引 : 復合索引,不要跨列或無序使用(最佳左前綴)
4.like語句操作: 一般情況下不鼓勵使用like操作,如果非使用不可,注意正確的使用方式。like ‘%aaa%’不會使用索引,而like ‘aaa%’可以使用索引。
5. 不要在索引上進行任何操作(計算、函數、類型轉換),否則索引失效
6.不使用NOT IN 、<>、!=操作,但<,<=,=,>,>=,BETWEEN,IN是可以用到索引的
7.索引要建立在經常進行select操作的字段上。
這是因為,如果這些列很少用到,那么有無索引並不能明顯改變查詢速度。相反,由於增加了索引,反而降低了系統的維護速度和增大了空間需求。
8.索引要建立在值比較唯一的字段上。
9.對於那些定義為text、image和bit數據類型的列不應該增加索引。因為這些列的數據量要么相當大,要么取值很少。
10.在join操作中(需要從多個數據表提取數據時),mysql只有在主鍵和外鍵的數據類型相同時才能使用索引,否則及時建立了索引也不會使用。
三, sql性能問題
a.分析SQL的執行計划 : explain ,可以模擬SQL優化器執行SQL語句,從而讓開發人員 知道自己編寫的SQL狀況
b.MySQL查詢優化其會干擾我們的優化(mysql服務層有一個sql優化器),可以對我們寫的sql進行優化,這是我們控制不了的。
查詢執行計划: explain +SQL語句 explain SELECT * from book ;
id : 編號
select_type :查詢類型
table :表
type :索引類型 system>const>eq_ref>ref>range>index>all ,要對type進行優化的前提:有索引 一般能達到range 就行。
possible_keys :預測用到的索引
key :實際使用的索引
key_len :實際使用索引的長度
ref :表之間的引用
rows :通過索引查詢到的數據量
Extra :額外的信息 下面是他可能發出的情況
i). using filesort : 性能消耗大;需要“額外”的一次排序(查詢) 。常見於 order by 語句中。 解決:where哪些字段,就order by那些字段2
ii). using temporary:性能損耗大 ,用到了臨時表。一般出現在group by 語句中。 解決: 避免:查詢那些列,就根據那些列 group by .
iii). using index :性能提升; 索引覆蓋(覆蓋索引)。原因:不讀取原文件,只從索引文件中獲取數據 (不需要回表查詢)
只要使用到的列 全部都在索引中,就是索引覆蓋using index
iii).using where (需要回表查詢)。
假設age是索引列
但查詢語句select age,name from ...where age =...,此語句中必須回原表查Name,因此會顯示using where. 解決 吧name 也添加到索引中去。