DDL(Data Definition Languages):數據定義語句,經常使用的語句關鍵字主要包括 create、drop、alter等操做表結構html
DML(Data Manipulation Language):數據操做語句,經常使用的語句關鍵字主要包括 insert、delete、udpate 和select 等操做數據mysql
DCL(Data Control Language):數據控制語句,用戶的訪問權限和安全級別。主要的語句關鍵字包括 grant、revoke 等算法
鏈接者:不一樣語言的代碼程序和mysql的交互(SQL交互)sql
鏈接池:管理、緩衝用戶的鏈接,線程處理等須要緩存的需求數據庫
管理服務和工具組件:系統管理和控制工具,例如備份恢復、Mysql複製、集羣等緩存
SQL接口:接受用戶的SQL命令,而且返回用戶須要查詢的結果安全
解析器:對SQL進行解析,判斷語法是否正確session
查詢優化器:SQL語句在查詢以前會使用查詢優化器對查詢進行優化數據結構
舉個例子併發
-- 下面的SQL company 和 name 都有索引,索引類型也相同,字段類型也相同 -- 索引字段能匹配的數據越少,優先使用該索引字段 select * from dept_table where company = '集團' and name = '財務部';
緩存:若是查詢緩存有命中的查詢結果,查詢語句就能夠直接去查詢緩存中取數據
存儲引擎:INSERT DELETE UPDATE SELECT 數據的一種方式
存儲引擎名稱 | 特色 | 應用場景 |
---|---|---|
InnoDB | 支持事務、行鎖、支持MVCC多版本併發控制,併發性高 | 應用OLTP業務系統 |
MyISAM | 不支持事務,MySQL8以後被廢棄了,併發很低,資源利用率也很低 | 應用OLAP業務系統,建議生產環境儘可能少少使用 MyISAM 存儲引擎 |
MariaDB columnstore | 列式存儲引擎,高壓縮功能 | 數據倉庫,OLAP業務系統 |
OLTP(On-Line Transaction Processing):聯機事務處理,好比增刪改查,完成一筆交易處理
OLAP(On-Line Analytical Processing):聯機分析處理,支持複雜的分析操做,側重決策支持,作數據分析,決策,好比 ElasticSearch
SQL執行過程
原子性(A):要麼全完成,要麼全不完成
一致性(C):在事務開始以前和事務結束之後,數據庫的完整性約束沒有被破壞(好比A給B轉帳100元,A減小100,B增長100)
隔離性(I):事務之間互不干擾
持久性(D):事務提交後保存起來了
讀未提交(read uncommitted):A事務變動後沒提交,B能看到
讀已提交(read committed):A事務變動後提交,B才能看到
可重複讀(repeatable read):一個事務執行過程當中看到的數據,老是跟這個事務在啓動時看到的數據是一致的
串行化(serializable):同一行記錄,「寫」會加「寫鎖」,「讀」會加「讀鎖」。當出現讀寫鎖衝突的時候,後訪問的事務必須等前一個事務執行完成,才能繼續執行
髒讀:讀未提交的隔離級別下,A事務讀到B更新卻沒commit的數據
不可重複讀:側重修改,A事務兩次讀取同一數據兩次不一致
幻讀:側重數據增減,A事務兩次讀取數據不一樣
事務隔離級別與併發問題
事務隔離級別 | 髒讀 | 不可重複讀 | 幻讀 |
---|---|---|---|
讀未提交(read uncommitted) | 是 | 是 | 是 |
讀已提交(read committed) | 否 | 是 | 是 |
可重複讀(repeatable read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
驗證事務的隔離級別
事務A | 事務B |
---|---|
begin; | begin; |
select * from dept_table; --V1 | |
select * from dept_table; --V2 | |
update dept_table set name = '研發部' where id = 1; | |
select * from dept_table; --V3 | |
commit; | |
select * from dept_table; --V4 | |
commit; | |
select * from dept_table; --V5 |
事務相關SQL
# 設置事務隔離級別 set session transaction isolation level read uncommitted; set session transaction isolation level read committed; set session transaction isolation level repeatable read; # 查詢當前事務隔離級別 select @@tx_isolation; # 查詢全局事務隔離級別 select @@global.tx_isolation; # 開啓事務 begin; start transaction; # 提交事務 commit; # 回滾事務 rollback;
多版本併發控制 MVCC(Multi-Version Concurrency Control): MySQL 的 InnoDB 存儲引擎實現隔離級別的一種具體方式,在每行數據都增長兩個隱藏字段,一個記錄建立的版本號,一個記錄刪除的版本號,用於實現提交讀和可重複讀這兩種隔離級別。而未提交讀隔離級別老是讀取最新的數據行,無需使用 MVCC。可串行化隔離級別須要對全部讀取的行都加鎖,單純使用 MVCC 沒法實現
系統版本號:是一個遞增的數字,每開始一個新的事務,系統版本號就會自動遞增
事務版本號:事務開始時的系統版本號
插入一條新數據(事務版本號 = 1)
id | name | create_version | delete_version |
---|---|---|---|
1 | Tom | 1 |
執行更新操做(事務版本號 = 2)
update table set name= 'Tom2' where id = 1;
id | name | create_version | delete_version |
---|---|---|---|
1 | Tom | 1 | 2 |
1 | Tom2 | 2 |
刪除操做(事務版本號 = 3)
delete from table where id = 1;
id | name | create version | delete version |
---|---|---|---|
1 | Tom2 | 2 | 3 |
查詢操做要知足兩個條件才能查詢出來
-- 1. T事務(假設:當前事務版本號 = 1)插入一條數據 -- create_version = 1 delete_version = null insert into `up`.`dept_table`(`id`, `company`, `name`) values (5, '總部', '綜合創新部'); -- 1. A事務(假設:當前事務版本號 = 2) 查詢數據 4條結果 select * from dept_table; -- 2. B事務(假設:當前事務版本號 = 3) 更新ID = 1 的數據 update dept_table set name = '金融服務部' where id = 5; -- 3. A事務繼續查詢 select * from dept_table;
當執行select操做時 InnoDB默認會執行快照讀,會記錄下此次select後的結果,以後select 的時候就會返回此次快照的數據,即便其餘事務提交了不會影響當前select的數據,這就實現了可重複讀了。快照的生成當在第一次執行select的時候,也就是說假設當A開啓了事務,而後沒有執行任何操做,這時候B insert了一條數據而後commit,這時候A執行 select,那麼返回的數據中就會有B添加的那條數據。以後不管再有其餘事務commit都沒有關係,由於快照已經生成了,後面的select都是根據快照來的
示例1 B事務的查詢結果是否有A新增的數據?
A事務 | B事務 |
---|---|
start transaction; | start transaction; |
insert into up .dept_table (id , company , name ) values (6, '總部', '綜合創新部'); |
|
select * from dept_table; | |
commit; | |
select * from dept_table; | |
commit |
示例2 B事務的兩次查詢結果是否相同?第二次查詢是否有A新增的數據?
A事務 | B事務 |
---|---|
start transaction; | start transaction; |
select * from dept_table; | |
insert into up .dept_table (id , company , name ) values (6, '總部', '綜合創新部'); |
|
select * from dept_table; | |
commit; | |
select * from dept_table; | |
commit; |
對數據修改的操做(update、insert、delete、select …... lock in share mode、select …... for update)都是採用當前讀的模式。在執行這幾個操做時會讀取最新的記錄,即便是別的事務提交的數據也能夠查詢到。假設要update一條記錄,可是在另外一個事務中已經delete掉這條數據而且commit了,若是update就會產生衝突,因此在update的時候須要知道最新的數據。也正是由於這樣因此才致使上面咱們測試的那種狀況
示例
A事務 | B事務 |
---|---|
start transaction; | start transaction; |
select * from dept_table; -- V1 | |
insert into up .dept_table (id , company , name ) values (6, '總部', '綜合創新部'); |
|
commit; | |
select * from dept_table; -- V2 | |
update dept_table set name = '新部門' where id = 6; | |
select * from dept_table; -- V3 | |
commit; |
快照讀 | 當前讀 |
---|---|
select * from table | select * from table for update |
select * from table lock in share mode | |
insert、delete、insert |
數據庫鎖機制簡單來講,就是數據庫爲了保證數據的一致性,使各類共享資源在被併發訪問時變得有序而設計的一種規則
MySQL的鎖機制比較簡單,最顯著的特色時不一樣的存儲引擎支持不一樣的鎖機制,咱們鎖知道的,InnoDB支持行鎖,有時也會升級爲表鎖,MyISAM只支持表鎖
表鎖 | 行鎖 |
---|---|
開銷小 | 開銷大 |
加鎖快 | 加鎖慢 |
不會出現死鎖 | 會出現死鎖 |
鎖粒度大 | 鎖粒度小 |
發生鎖衝突的機率高 | 發生鎖衝突的機率低 |
併發度相對低 | 併發度相對高 |
簡稱S鎖,若事務T對數據對象加上讀鎖,則事務T能夠讀但不能修改,其餘事務只能再對該數據加讀鎖不能加寫鎖,直到T釋放該數據的讀鎖。即一個事務在讀取一個數據行時,其餘事務也能夠讀,但不能對該數據進行增刪改的操做
讀鎖的實現方式
-- 查詢是否自動提交模式 show variables like '%auto%';
簡稱X鎖,若事務T對數據對象加上寫鎖,事務T能夠讀也能夠修改,其餘事務不能再對該數據加任何鎖,不能讀也不能寫,直到T釋放該數據上的鎖。即一個事務獲取了一個數據行的寫鎖,其餘事務就不能再獲取該行的其餘鎖,寫鎖優先級最高
寫鎖的實現方式
在事務A中開啓查詢,會自動得到一個MDL鎖,事務B就不能夠執行任何DDL語句的操做
事務A | 事務B |
---|---|
begin; | begin; |
select * from score_table; | |
alter table score_table add num tinyint(1) not null default 0; -- 阻塞 | |
commit; | |
commit; |
-- 查詢進程列表 show full processlist;
在MySQL存儲引擎InnoDB中,意向鎖是表級鎖。並且有兩種意向鎖類型,分別爲意向共享鎖和意向排他鎖
其實意向鎖的做用跟MDL鎖相似,都是防止在事務進行過程當中,執行DDL語句的操做而致使數據不一致
在默認的事務隔離級別爲RR,而且參數 innodb_locks_unsafe_for_binlog = 0 的模式下,行鎖的種類有三種
注:主鍵和惟一索引都是行記錄的鎖模式。在RC隔離級別下,只有 record lock 記錄鎖模式
注:普通索引默認的就是 next-key lock模式
-- 查看索引 show index from dept_table;
company 字段有索引
事務A | 事務B |
---|---|
begin; | begin; |
update score_table set name = 'a' where score= 60; | |
update score_table set name = 'aaa' where score= 60; -- 出現鎖等待 | |
update score_table set name = 'bbb' where score= 70; -- 正常更新 | |
commit; | |
commit; |
company 字段無索引
事務A | 事務B |
---|---|
begin; | begin; |
update score_table set name = 'a' where score= 60; | |
update score_table set name = 'bbb' where score= 70; -- 出現鎖等待 | |
commit; | |
commit; |
InnoDB的鎖是加在索引上的
在RR事務隔離級別,爲了不幻讀現象,引入了 gap lock,但它只鎖定記錄的範圍,不包含記錄自己,即不容許在次範圍內插入任何數據
事務隔離級別RR
事務A | 事務B |
---|---|
begin; | begin; |
select * from score_table where score < 80 lock in share mode; | |
insert into score_table(name, score) values ('dd', 75); -- 等待 | |
commit; | |
commit; |
事務隔離級別RC
-- 查看事務隔離級別 show variables like '%tx_isolation%';
事務A | 事務B |
---|---|
begin; | begin; |
set session transaction isolation level read committed; | set session transaction isolation level read committed; |
select * from score_table where score < 80 lock in share mode; | |
insert into score_table(name, score) values ('dd', 75); -- 可提交 | |
commit; | |
commit; |
證實間隙鎖只是針對RR隔離級別才管用,從鎖的角度避免了幻讀發生
記錄鎖與間隙鎖的組合,當InnoDB掃描表記錄時,會先對選中的索引加上記錄鎖,再對索引記錄兩邊的間隙加上間隙鎖
事務A | 事務B |
---|---|
begin; | begin; |
select * from score_table where score < 85 for update; | |
insert into score_table(name, score) values ('dd', 85); -- 等待 | |
commit; | |
commit; |
證實不光鎖定 score < 85 這個區間的數據,還包含 85 這個值的自己
鎖等待是指一個事務過程當中產生的鎖,其餘事務須要等待上一個事務釋放它的鎖,才能佔用該資源。若是該事務一直不釋放,就須要持續等待下去,直到超過鎖等待時間,會報一個等待超時的錯誤
-- 查詢鎖等待時間 show variables like '%innodb_lock_wait%'; -- 修改全局變量方式 set global innodb_lock_wait_timeout = 2; set @@global.innodb_lock_wait_timeout = 5; -- 修改當前事務變量方式 set innodb_lock_wait_timeout = 2;
死鎖是指兩個或兩個以上的進程在執行過程當中,因爭奪資源而形成的一種互相等待的現象,即事務1鎖住數據D1,正請求對D2加鎖,而事務2鎖住了D2,正請求加鎖D1,這樣就會致使死鎖
事務A | 事務B |
---|---|
begin; | begin; |
update score_table set name = 'a' where score= 60; | |
update score_table set name = 'bbb' where score= 70; | |
update score_table set name = 'b' where score= 70; | |
update score_table set name = 'aaa' where score= 60; | |
commit; | |
commit; |
-- 查看死鎖展現信息 show engine innodb status;
在工做中,開發人員在開發初期因爲多種緣由設計表的過程當中,沒有給後面可能會常常訪問的字段增長索引這個概念,因爲後期的業務調整需求變動且數據也在不斷增加,會根據某些已存在的字段做爲條件查詢。後面再增長索引會很麻煩,須要考慮現有系統的可用性,還須要考慮到當前增長索引列的內容。因此建立索引須要結合現有業務還要預知後期可能存在的業務變動,使設計的數據表伸縮性更強,在設計初期把數據表設計完善也可以讓後面的開發事半功倍。
索引利用好了就是一輛」法拉利「,利用很差就成了」三輪車「了。
幫助MySQL作高效查詢的一種數據結構,比如是一本書的目錄,經過目錄能快速找到要查看的內容
提升查詢效率
從存儲結構劃分:BTree索引(B-Tree或B+Tree索引),Hash索引
從應用層劃分:主鍵索引,惟一索引,普通索引,複合索引,全文索引,SPATIAL
根據鍵值的邏輯順序和表數據行的物理存儲順序:彙集索引,非彙集索引
彙集索引:葉子節點存放表中全部行數據記錄的信息
非彙集索引:不是彙集索引就是非彙集索引
索引通常在 where,order by,group by,錶鏈接的條件列起做用
索引無效:
-- 1. 查詢條件的值是null explain select * from dept_table where name = null; -- 2. NOT條件 好比:<>、in、not in、exists、not exists explain select * from dept_table where name <> '新部門'; explain select * from dept_table where name in ('財務部2'); -- 可使用索引 explain select * from dept_table where name in ('財務部2', '新部門'); -- 不使用索引 explain select * from dept_table where name not in ('新部門'); -- 一個和多個都不使用索引 explain select * from dept_table where exists (select * from dept_table where name = '新部門'); explain select * from dept_table where not exists (select * from dept_table where name = '新部門'); -- 3. LIKE通配符在前面 explain select * from dept_table where name like '%部門'; explain select * from dept_table where name like '部門%'; -- 可使用索引 explain select * from dept_table where name like '新%門%'; -- 可使用索引 -- 4. 條件列上包括函數 explain select * from dept_table where upper(name) = 'NEW'; explain select * from dept_table where name = upper('new'); -- 可使用索引
索引是存儲到磁盤上的文件
MyISAM引擎和InnoDB引擎共有文件
.frm文件:在MYSQL中創建任何一張數據表,在其數據目錄對應的數據庫目錄下都有對應表的.frm文件,.frm文件是用來保存每一個數據表的元數據(meta)信息,包括表結構的定義等,.frm文件跟數據庫存儲引擎無關,也就是任何存儲引擎的數據表都必須有.frm文件,命名方式爲數據表名.frm,如user.frm. .frm文件能夠用來在數據庫崩潰時恢復表結構
InnoDB引擎文件
.ibd文件:單表表空間文件,每一個表使用一個表空間文件(file per table),存放用戶數據庫表數據和索引
MyISAM引擎
.MYD:即 my data,表數據文件
.MYI:即 my index,索引文件
推薦一個數據結構網站:www.cs.usfca.edu/~galles/visualization/Algorithms.html
若有 三、一、二、十、九、0、四、6這8個數據
哈希結構
二叉樹結構(右子樹大於左子樹)
不使用二叉樹緣由:若是索引列查入的數據是單邊增加的,會致使查詢時依舊變慢,最差狀況時間複雜度會變成O(N)
紅黑樹結構(是一種平衡的二叉查找樹)
特色:
MySQL的數據實際是存儲在文件中,而磁盤IO的查找速度是要遠小於內存速度的,因此減小磁盤IO的次數能很大程度的提升MySQL性能
磁盤IO時間 = 尋道 + 磁盤旋轉 + 數據傳輸時間
從磁盤讀取數據時,系統會將邏輯地址發給磁盤,磁盤將邏輯地址轉換爲物理地址(哪一個磁道,哪一個扇區)。 磁頭進行機械運動,先找到相應磁道,再找該磁道的對應扇區,扇區是磁盤的最小存儲單元
性能對比
機械硬盤的連續讀寫性能很好,但隨機讀寫性能不好。
隨機讀寫時,磁頭須要不停的移動,時間都浪費在了磁頭尋址上。 而在實際的磁盤存儲裏,是不多順序存儲的,由於這樣的維護成本會很高
因爲存儲介質的特性,磁盤自己存取就比主存慢不少,再加上機械運動耗費,磁盤的存取速度每每是主存的幾百分分之一,所以爲了提升效率,要儘可能減小磁盤I/O。爲了達到這個目的,磁盤每每不是嚴格按需讀取,而是每次都會預讀,即便只須要一個字節,磁盤也會從這個位置開始,順序向後讀取必定長度的數據放入內存。這樣作的理論依據是計算機科學中著名的局部性原理:
當一個數據被用到時,其附近的數據也一般會立刻被使用。
程序運行期間所須要的數據一般比較集中。
因爲磁盤順序讀取的效率很高(不須要尋道時間,只需不多的旋轉時間),所以對於具備局部性的程序來講,預讀能夠提升I/O效率。
預讀的長度通常爲頁(page)的整倍數。頁是計算機管理存儲器的邏輯塊,硬件及操做系統每每將主存和磁盤存儲區分割爲連續的大小相等的塊,每一個存儲塊稱爲一頁(在許多操做系統中,頁得大小一般爲4k),主存和磁盤以頁爲單位交換數據。當程序要讀取的數據不在主存中時,會觸發一個缺頁異常,此時系統會向磁盤發出讀盤信號,磁盤會找到數據的起始位置並向後連續讀取一頁或幾頁載入內存中,而後異常返回,程序繼續運行。
度(m):節點數據存儲個數
深度關係(h):h=log(m+1)N
B+Tree相對於BTree區別:
MyISAM引擎使用B+Tree做爲索引結構,葉節點的data域存放的是數據記錄的地址
這裏設表一共有三列,假設咱們以Col1爲主鍵,上圖是一個MyISAM表的主索引(Primary key)示意。能夠看出MyISAM的索引文件僅僅保存數據記錄的地址。在MyISAM中,主索引和輔助索引(Secondary key)在結構上沒有任何區別,只是主索引要求key是惟一的,而輔助索引的key能夠重複。若是咱們在Col2上創建一個輔助索引,則此索引的結構以下圖所示
一樣也是一顆B+Tree,data域保存數據記錄的地址。所以,MyISAM中索引檢索的算法爲首先按照B+Tree搜索算法搜索索引,若是指定的Key存在,則取出其data域的值,而後以data域的值爲地址,讀取相應數據記錄
因此MyISAM是非「彙集索引」,從索引文件和數據文件分別存儲就能夠看出。也與下面介紹的InnoDB的「彙集索引」作區分
雖然InnoDB也使用B+Tree做爲索引結構,但具體實現方式卻與MyISAM大相徑庭
第一個不一樣:MyISAM索引文件和數據文件是分離的,索引文件僅保存數據記錄的地址。InnoDB的數據文件自己就是索引文件,從文件存儲上就能夠知道,表數據文件自己就是按B+Tree組織的一個索引結構,這棵樹的葉節點data域保存了完整的數據記錄。這個索引的key是數據表的主鍵,所以InnoDB表數據文件自己就是主索引
InnoDB主索引(同時也是數據文件)的示意圖
能夠看到葉節點包含了完整的數據記錄。這種索引叫作彙集索引。由於InnoDB的數據文件自己要按主鍵彙集,因此InnoDB要求表必須有主鍵(MyISAM能夠沒有),若是沒有顯式指定,則MySQL系統會自動選擇一個能夠惟一標識數據記錄的列做爲主鍵,若是不存在這種列,則MySQL自動爲InnoDB表生成一個隱含字段做爲主鍵,這個字段長度爲6個字節,類型爲長整形。
第二個不一樣:與MyISAM索引的不一樣是InnoDB的輔助索引data域存儲相應記錄主鍵的值而不是地址。換句話說,InnoDB的全部輔助索引都引用主鍵做爲data域
InnoDB輔助索引(輔助索引得到主鍵索引)的示意圖
這裏以英文字符的ASCII碼做爲比較準則。彙集索引這種實現方式使得按主鍵的搜索十分高效,可是輔助索引搜索須要檢索兩遍索引:首先檢索輔助索引得到主鍵,而後用主鍵到主索引中檢索得到記錄。
空間方面:uuid存儲空間更大
比較關係:索引之間有比較關係,整型的比較會更快
結構方面(最重要一點):使用自增主鍵保證插入數據都是向葉子節點後面順序插入,若是使用uuid比較,生成的uuid不必定順序插入,致使插入到節點的中間位置,若是該節點已經滿了,會致使節點進行分裂變成新的結構
一致性和節省存儲空間
B-Tree節點的度設置等於一個頁,每次新建節點直接申請一個頁的空間,這樣就保證一個節點物理上也存儲在一個頁裏,就實現了一個節點的載入只須要載入一次I/O
redolog:數據日誌
undolog:ibdata1
binlog:邏輯日誌