Java 程序員應(yīng)掌握的 MySQL 數(shù)據(jù)庫知識

前言

MySQL 是一款開源軟件半抱,憑借其出色的性能,目前已經(jīng)成為絕大多數(shù)互聯(lián)網(wǎng)公司的首選關(guān)系型數(shù)據(jù)庫。因此程序員不能只懂?dāng)?shù)據(jù)庫的增刪改查和一些簡單的使用技巧疗我,更需要熟練掌握 MySQL 的一些原理知識仔夺,從而更好地應(yīng)對實際工作中遇到的問題琐脏。

本文為大家介紹 MySQL 的知識點包括:

  1. 了解 MySQL 官網(wǎng)以及 MySQL 下載,MySQL 文檔
  2. 了解 MySQL 的架構(gòu)
  3. 了解 MySQL 的存儲引擎
  4. 掌握 MyISAM 與 InnoDB 引擎的區(qū)別以及數(shù)據(jù)文件存放路徑
  5. 了解 InnoDB 的邏輯存儲結(jié)構(gòu)
  6. 掌握 MySQL 中 SQL 語句的執(zhí)行過程
  7. 了解 MySQL 的緩存機制
  8. 認(rèn)識數(shù)據(jù)庫索引的本質(zhì)
  9. 認(rèn)識四種樹的數(shù)據(jù)結(jié)構(gòu)(二叉查找樹缸兔、平衡二叉樹日裙、B-Tree、B+Tree)
  10. 掌握 MySQL 中 B+Tree 索引的實現(xiàn)方式
  11. 深入理解數(shù)據(jù)庫索引的幾個概念
  12. 掌握索引的創(chuàng)建原則以及注意事項
  13. 深入理解數(shù)據(jù)庫的事務(wù)
  14. 掌握事務(wù)的 ACID 特性與事務(wù)的隔離級別
  15. 了解并發(fā)給數(shù)據(jù)庫帶來的問題
  16. 了解 InnoDB 存儲引擎支持的隔離級別
  17. 掌握 MySQL 中鎖的機制
  18. 了解 MySQL 中四個事務(wù)隔離級別的實現(xiàn)
  19. 掌握 MVCC 的實現(xiàn)原理
  20. 理解 Undo Log惰蜜、Redo Log 的作用
  21. 掌握 SQL 語句調(diào)優(yōu)中 explain 的用法
  22. 掌握 MySQL 常用的調(diào)優(yōu)策略

適合人群: 有 MySQL 使用經(jīng)驗昂拂,想要深入了解 MySQL 的架構(gòu)、索引抛猖、事務(wù)格侯、性能優(yōu)化的程序員。

本文以理論介紹為主财著,大約 1.8 萬字联四,建議大家分章節(jié)閱讀。

一瓢宦、MySQL 官網(wǎng)介紹碎连,了解 MySQL 的整體架構(gòu)

1、MySQL 官網(wǎng)介紹

學(xué)習(xí)了解一個技術(shù)最好的方式是通過官網(wǎng)去了解驮履,官網(wǎng)上有詳細(xì)的文檔資料可供學(xué)習(xí)鱼辙。很對人不習(xí)慣從官網(wǎng)上查找資料廉嚼,甚至不清楚如何在官網(wǎng)上下載程序安裝包,如何找到官方的學(xué)習(xí)文檔倒戏,下面給大家做個簡單的介紹怠噪。面對復(fù)雜的英文文檔,大家不必發(fā)憷杜跷,看的多了就習(xí)慣了傍念,實在看不了,不是還有谷歌翻譯嗎葛闷。

1.1憋槐、MySQL 下載

MySQL 官網(wǎng)地址:https://dev.mysql.com/

打開后界面如下:其中 DOWNLOADS 和 DOCUMENTATION 兩個標(biāo)簽就是下載和文檔的入口。
在這里插入圖片描述

打開 DOWNLOADS 頁面淑趾,找到最下方的 MySQL Community (GPL) Downloads 阳仔,下載社區(qū)版即可,免費使用扣泊。

MySQL 下載地址:https://dev.mysql.com/downloads/mysql/ 打開后點擊:MySQL Community Server 近范,點擊 Looking for previous GA versions? 選擇 MySQL 的歷史通用版本。

在這里插入圖片描述

在這里插入圖片描述

下載時需要注冊 Oracle 的賬戶延蟹。

1.2评矩、MySQL 文檔

在這里插入圖片描述

從左邊的菜單選擇感興趣的內(nèi)容可以進(jìn)行學(xué)習(xí)。
在這里插入圖片描述

2阱飘、了解 MySQL 的架構(gòu)

在 MySQL5.1 的中文文檔資料里斥杜,有如下的一張 MySQL 插件式存儲引擎的體系結(jié)構(gòu)圖,通過這張圖(https://www.mysqlzh.com/doc/134.html)俯萌, 我們能很好的了解 MySQL 的整體架構(gòu)果录。

2.1 MySQL 架構(gòu)圖

在這里插入圖片描述

從以上的架構(gòu)圖我們可以看出,最上面的 Connectors 表示客戶端咐熙,客戶端就是一些具體的鏈接協(xié)議弱恒;下面的 MySQL Server 表示服務(wù)端,其中包括 Connection Pool 棋恼、SQL Interface返弹、Parser、Optimizer爪飘、Storage Engines义起、文件系統(tǒng)(Files、Logs)以及管理服務(wù)师崎。

2.2默终、MySQL 架構(gòu)介紹

從上面的分析可以看出,MySQL 服務(wù)器主要包括 sql 層和存儲引擎層,主要包括以下 6 個部分:

1齐蔽、客戶端的鏈接支持的協(xié)議很多两疚,比如我們在 Java 開發(fā)中經(jīng)常用到的 JDBC,客戶端請求過來首先會由 Connection Pool 進(jìn)行管理含滴,包括權(quán)限認(rèn)證诱渤、鏈接管理,緩存管理等谈况,Connection Pool 最主要的功能就是接收客戶端的請求勺美。

2、客戶端一個 sql 語句請求過來之后碑韵, SQL Interface 會統(tǒng)一接收用戶的 sql 命令赡茸,接下來會交給 Parser 來進(jìn)行解析。

3泼诱、Parser 解析器的目的是把 sql 的文本解析成 selectlex 對象坛掠,隨后把 selectlex 對象提交給優(yōu)化器 Optimizer。

4治筒、優(yōu)化器 Optimizer 會進(jìn)行 sql 執(zhí)行的成本計算,找到最優(yōu)的一個執(zhí)行計劃舷蒲,然后會調(diào)用下方存儲引擎 Storage Engines 的 API 進(jìn)行數(shù)據(jù)的讀寫耸袜。

5、存儲引擎 Storage Engines 最終操作的是最下方的文件系統(tǒng)牲平,包括 Files 和 Logs堤框。

6、圖中左上角的工具模塊包括備份纵柿、主從復(fù)制等功能蜈抓。

二、了解 MySQL 的存儲引擎

存儲引擎的主要工作就是與文件系統(tǒng)進(jìn)行數(shù)據(jù)交互昂儒,比如我們常用的 InnoDB 引擎沟使。

MySQL 的存儲引擎是插件式的,應(yīng)用程序無需針對不同的存儲引擎進(jìn)行對應(yīng)的編碼操作渊跋,MySQL 提供了一套標(biāo)準(zhǔn)的 API 標(biāo)準(zhǔn)腊嗡,MySQL 服務(wù)會自動處理不同的存儲引擎與文件系統(tǒng)的讀寫,用戶層面沒有感知拾酝。

存儲引擎是指定在表上面的燕少,每個表都可以指定其自己的引擎;不管使用什么存儲引擎蒿囤,都會產(chǎn)生一個后綴為 frm 的文件客们,改用來定義表結(jié)構(gòu)。

1、MySQL 的存儲引擎介紹

存儲引擎名稱 特點
1 MyISAM Mysql5.5 版本之前的默認(rèn)存儲引擎
2 InnoDB Mysql5.5 及以后版本的默認(rèn)存儲引擎底挫,目前用的最多的一個存儲引擎
3 CSV 數(shù)據(jù)存儲以 CSV 文件恒傻,不適用大表或者數(shù)據(jù)的在線處理
適用于數(shù)據(jù)的快速導(dǎo)入與導(dǎo)出
4 Memory 數(shù)據(jù)都是存儲在內(nèi)存中,服務(wù)重啟數(shù)據(jù)丟失凄敢,默認(rèn) 16M 空間碌冶,
可用于查詢結(jié)果內(nèi)存計算,創(chuàng)建臨時表存儲需要計算的數(shù)據(jù)
5 Archive 數(shù)據(jù)存儲為 ARZ 文件格式涝缝,只支持 insert 和 select 兩種操作
可用于數(shù)據(jù)備份

2扑庞、掌握 MyISAM 與 InnoDB 引擎的區(qū)別

Mysql5.5 版本之前默認(rèn)的存儲引擎就是 MyISAM 存儲引擎,MySQL 中比較多的系統(tǒng)表使用 MyISAM 存儲引擎拒逮,系統(tǒng)臨時表也會用到 MyISAM 存儲引擎罐氨,但是在 Mysql5.5 之后默認(rèn)的存儲引擎就是 InnoDB 存儲引擎了。原因主要是 MyISAM 是表級鎖定滩援,限制了數(shù)據(jù)庫讀/寫的性能栅隐;另外一個原因 MyISAM 不支持事務(wù),基于以上兩點玩徊,InnoDB 引擎使用的非常廣泛租悄。

對比 InnoDB MyISAM
文件存儲方式 .frm 表定義文件;.ibd 數(shù)據(jù)文件 .frm 表定義文件恩袱;.myd 數(shù)據(jù)文件泣棋;.myi 索引文件
索引方式 B+ Tree B+ Tree
count(*) 操作 全表掃描 無需掃描
鎖機制 表鎖、 行鎖 表鎖
事務(wù) 支撐事務(wù)的 ACID 不支持事務(wù)
常用場景 讀寫操作 讀多寫少操作畔塔,比如配置表

3潭辈、MyISAM 與 InnoDB 數(shù)據(jù)文件存放路徑

-- 查看數(shù)據(jù)存儲的文件路徑
show variables like 'datadir';

4、InnoDB 邏輯存儲結(jié)構(gòu)

MySQL 的存儲結(jié)構(gòu)分為 5 級:表空間澈吨、段把敢、簇、頁谅辣、行修赞。

表空間(TableSpace): 表空間可以看做是 InnoDB 存儲引擎邏輯結(jié)構(gòu)的存儲結(jié)構(gòu)的大容器,所有的數(shù)據(jù)都存放在表空間中屈藐,分為:系統(tǒng)表空間榔组、獨占表空間、通用表空間联逻、臨時表空間搓扯、Undo 表空間。

段(Segment): 表空間是由各個段組成的包归,分為:數(shù)據(jù)段锨推、索引段、回滾段等,段是一個邏輯的概念换可,一個 .ibd 文件(獨立表空間文件)里面會由很多個段組成椎椰。創(chuàng)建一個索引會創(chuàng)建兩個段,一個是索引段(leaf node segment)沾鳄,索引段管理非葉子節(jié)點的關(guān)鍵字和引用數(shù)據(jù)慨飘;一個是數(shù)據(jù)段:(non-leaf node segment),數(shù)據(jù)段管理葉子節(jié)點的行記錄數(shù)據(jù)译荞。

區(qū)/簇(extents): 一個段由很多的簇(也可以叫區(qū))組成瓤的,每個區(qū)的大小是 1MB(64 個連續(xù)的頁),每一個段至少會有一個簇吞歼,一個段所管理的空間大小是無限的圈膏,可以一直擴展下去,但是擴展的最小單位就是簇篙骡。

頁/塊(page): 為了高效管理物理空間稽坤,簇是由連續(xù)的頁組成的空間,一個簇中有 64 個連續(xù)的頁(1MB/16 KB = 64)糯俗,這些頁面在物理上和邏輯上都是連續(xù)的尿褪。頁是 InnoDB 存儲引擎磁盤管理的最小單位,每個頁默認(rèn) 16KB得湘,通過 innodbpagesize 設(shè)置茫多。

行(Row): MySQL5.7 以后默認(rèn)的行格式(Rowformat)為:DYNAMIC,Rowformat 可在創(chuàng)建數(shù)據(jù)表時指定忽刽,大家了解有這么一回事就可以了。

文件系統(tǒng)中夺欲,操作系統(tǒng)和內(nèi)存進(jìn)行文件交換跪帝,最小的單位也是頁,不過文件系統(tǒng)的頁默認(rèn)是 4KB些阅,MySQL 數(shù)據(jù)庫的頁默認(rèn)是 16KB伞剑,目的是為了一次 IO 操作可以獲取更多的數(shù)據(jù)。

三市埋、了解 SQL 語句在 MySQL 中的執(zhí)行過程

作為開發(fā)人員都非常清楚黎泣,當(dāng)我們寫好一個 sql 語句之后,連接到數(shù)據(jù)庫點擊執(zhí)行缤谎,數(shù)據(jù)庫就會返回我們要查詢或者更新的結(jié)果抒倚。但是,數(shù)據(jù)庫服務(wù)器在接收到一個 sql 請求后內(nèi)部是如何處理的坷澡,可能就不太清楚了托呕。這一節(jié)主要為大家講解從客戶端發(fā)起一個 sql 語句的查詢悬嗓,數(shù)據(jù)庫服務(wù)器內(nèi)部的一個處理流程。

1司顿、 MySQL 中 SQL 語句的執(zhí)行過程

一個 MySQL 請求的處理流程圖:
在這里插入圖片描述

從上圖可以看出锰镀,MySQL 的處理流程主要分為 4 個步驟:客戶端與服務(wù)端通信、查詢優(yōu)化處理過程着降、查詢執(zhí)行引擎差油、返回結(jié)果給客戶端。

1.1任洞、客戶端與服務(wù)端通信

一般通信方式有 3 種:單工蓄喇,半雙工,全雙工侈咕。單工就是只能單向傳輸公罕,要么 A 端給 B 端傳輸,要么 B 端給 A 端傳輸耀销;半雙工是可以雙向傳輸?shù)穆ゾ欤峭粫r間只能是一個方向傳輸,也就是說 A 端給 B 端傳輸?shù)臅r候熊尉,B 端只能等待罐柳,反過來也一樣,B 端給 A 端傳輸?shù)臅r候狰住,A 端也只能等待张吉;全雙工是雙向隨便傳輸。

MySQL 客戶端與服務(wù)器的通信方式是半雙工的催植,也就是說肮蛹,我們的一個數(shù)據(jù)庫連接在向數(shù)據(jù)庫發(fā)送數(shù)據(jù)的時候,此時這個數(shù)據(jù)庫連接是不能給客戶端返回數(shù)據(jù)的创南,一定是數(shù)據(jù)返回完畢以后伦忠,客戶端才能再次發(fā)起查詢操作。這也就是我們在做數(shù)據(jù)查詢的時候用 where 條件 和 limit 限制數(shù)據(jù)結(jié)果行數(shù)的原因稿辙,否則客戶端連接需要等到數(shù)據(jù)庫把所有的查詢結(jié)果返回之后昆码,才能進(jìn)行下一個操作。

從上面的分析可以看出邻储,MySQL 數(shù)據(jù)庫半雙工通信模式的一個重要特點是:客戶端一旦開始發(fā)送指令赋咽,服務(wù)端需要接收完畢才能響應(yīng),客戶端只有在完全接收到服務(wù)端響應(yīng)的數(shù)據(jù)后吨娜,才能再次發(fā)送指令脓匿。有點像對講機,這就是為什么電視里看到兩個人對講時萌壳,最后要說一句 over 的原因亦镶,當(dāng)聽到 over 的時候日月,另一端的人就可以按對講鍵進(jìn)行說話了。我們在程序開發(fā)中缤骨,一般會用多個連接進(jìn)行數(shù)據(jù)交互爱咬,通過數(shù)據(jù)庫連接池來進(jìn)行管理,因此對這塊體會可能不夠深刻绊起。

其實 MySQL 的每一個連接都有其對應(yīng)的狀態(tài)來標(biāo)識它目前所處的階段精拟,和線程類似,我們可以通過下面的命令查看數(shù)據(jù)庫連接的狀態(tài):

SHOW [FULL] PROCESSLIST

常用的幾個狀態(tài)描述:

狀態(tài)值 狀態(tài)描述
1 login 連接線程的初始狀態(tài)虱歪,直到客戶端已成功通過身份驗證
2 executing 該線程已開始執(zhí)行一條語句
3 optimizing 服務(wù)器正在對查詢執(zhí)行初始優(yōu)化
4 Updating 線程正在搜索或者更新要更新的行
5 Sending data 正在將數(shù)據(jù)發(fā)送到客戶端蜂绎,一般會執(zhí)行大量的磁盤訪問操作
6 Sorting result 正在對結(jié)果排序
7 Waiting for commit lock 正在等待提交鎖

當(dāng)發(fā)現(xiàn)數(shù)據(jù)庫連接長時間占用的時候,可以用 kill 命令殺死線程:

kill processlist_id

1.2笋鄙、查詢優(yōu)化處理過程

解析器解析 sql 語句:通過 lex 詞法分析器(就是把一個完整的 SQL 語句分析成獨立的單詞 )师枣、yacc 語法分析器(就是分析是否符合語法規(guī)則,比如單引號是否閉合等)進(jìn)行分析萧落,將 sql 語句按 sql 標(biāo)準(zhǔn)解析成 解析樹(select_lex)對象践美,主要功能是把一個 sql 語句的字符串解析成數(shù)據(jù)庫服務(wù)器可以處理的解析樹對象,便于后續(xù)進(jìn)行預(yù)處理和生成執(zhí)行計劃找岖。

預(yù)處理:預(yù)處理會根據(jù) mysql 的語法規(guī)則對解析樹對象進(jìn)行合法性檢查陨倡,比如檢查表名列名是否存在、檢查名字和別名许布,保證沒有歧義兴革,預(yù)處理之后得到一個新的解析樹。

優(yōu)化器生成執(zhí)行計劃:優(yōu)化器的主要作用就是把這個 sql 語句找到最優(yōu)的執(zhí)行計劃蜜唾,MySQL 的查詢優(yōu)化器和 Oracle 類似杂曲,都是基于成本的計算,優(yōu)化器會嘗試使用不同的執(zhí)行計劃袁余,以便于找到一個最優(yōu)的執(zhí)行計劃(一般隨機讀取 4K 的數(shù)據(jù)庫進(jìn)行分析)解阅。

可以使用以下的命令查看查詢的成本:

show status like 'Last_query_cost';

優(yōu)化器最終會把解析樹變成一個查詢執(zhí)行計劃。MySQL 提供了一個執(zhí)行計劃的工具泌霍,我們在 SQL 語句前面加上 EXPLAIN,就可以看到執(zhí)行計劃的信息述召。

我們在做 sql 調(diào)優(yōu)的時候主要也就是對這部分進(jìn)行處理朱转,在《掌握 SQL 語句調(diào)優(yōu)中 explain 的用法》中會詳細(xì)介紹。

1.3积暖、查詢執(zhí)行引擎

查詢執(zhí)行模塊藤为,也就是查詢執(zhí)行引擎,根據(jù)優(yōu)化器生成的最優(yōu)執(zhí)行計劃調(diào)用對應(yīng)存儲引擎的 API 的進(jìn)行執(zhí)行計劃的執(zhí)行夺刑,并獲取查詢應(yīng)該返回的結(jié)果集缅疟。

1.4分别、返回結(jié)果給客戶端

如果沒有開啟緩存,把查詢到的結(jié)果集返回到客戶端存淫;如果開啟了緩存耘斩,執(zhí)行緩存操作,把結(jié)果集存入緩存桅咆,然后把結(jié)果返回給客戶端括授,即使結(jié)果集是空的,也要返回岩饼。

2荚虚、MySQL 的緩存介紹

一般情況下,我們不會用到數(shù)據(jù)庫自帶的緩存籍茧,所以 MySQL 默認(rèn)是不開啟緩存的版述。只有以讀為主的業(yè)務(wù),數(shù)據(jù)不變化的情況下寞冯,可以開啟數(shù)據(jù)庫的緩存渴析。

查看緩存是否開啟:

show variables like 'query_cache%';

queyrcachetype:on,表示緩存開啟简十,默認(rèn)是關(guān)閉的檬某,可以通過修改 MySQL 配置文件 my.cnf 進(jìn)行調(diào)整,重啟服務(wù)后生效螟蝙。

querycachelimit:1048576恢恼,表示單詞查詢緩存的結(jié)果集大小 1M,超過 1M 則不會緩存胰默。

querycachesize场斑,表示緩存開辟的空間大小

查看緩存操作情況:

show status like 'Qcache%';

Qcache_hits:表示緩存命中次數(shù)

Qcache_inserts:表示緩存寫入次數(shù)

緩存生效的條件是在緩存開啟的情況下,執(zhí)行的 sql 語句字符串一模一樣的時候牵署,可以從緩存直接讀取數(shù)據(jù)漏隐,但是當(dāng)緩存數(shù)據(jù)相關(guān)的表存在數(shù)據(jù)變化的時候,原有的緩存就會失效奴迅,需要重新寫人緩存青责。

MySQL 的緩存開啟后,當(dāng) sql 查詢語句帶有 sqlnocache 關(guān)鍵字或者帶有函數(shù)操作或者單次查詢結(jié)果集超過 querycachelimit 的設(shè)置的值或者查詢系統(tǒng)表時取具,不會用到緩存脖隶。

我們在開發(fā)中,最好不要開啟緩存暇检,將 querycachetype 設(shè)置為 off产阱,querycachesize 設(shè)置為 0;緩存一般會用 Redis 方案來替代块仆。

四构蹬、索引的本質(zhì)與數(shù)據(jù)結(jié)構(gòu)

正確合理的創(chuàng)建索引是提升數(shù)據(jù)庫查詢性能的基礎(chǔ)王暗,因此針對數(shù)據(jù)庫來說,索引是必須要掌握的庄敛。

1俗壹、數(shù)據(jù)庫索引的本質(zhì)

我們一說到索引,如果大家想到是一個類似于字典的目錄铐姚,可以提高數(shù)據(jù)庫查詢的性能策肝,那么這個理解還是太表面了,也就是說對索引的作用有了解隐绵,對它的本質(zhì)還是不夠了解之众。

數(shù)據(jù)庫索引的本質(zhì)是一種數(shù)據(jù)結(jié)構(gòu),是數(shù)據(jù)庫管理系統(tǒng)(DBMS)中一個排序的數(shù)據(jù)結(jié)構(gòu)依许,目的是為了提升對數(shù)據(jù)庫表中的記錄行的檢索速度棺禾,以協(xié)助快速查詢、更新數(shù)據(jù)庫表中數(shù)據(jù)峭跳,而創(chuàng)建的一種數(shù)據(jù)結(jié)構(gòu)膘婶。

實際上,建立索引會占用磁盤空間的索引文件蛀醉,索引也是一張表悬襟,該表保存了主鍵與索引字段,并指向?qū)嶓w表的記錄地址拯刁。

使用索引提升查詢效率的 3 個特點:

1脊岳、索引能極大的減少存儲引擎需要掃描的數(shù)據(jù)量,從而提升查詢效率垛玻;

2割捅、索引可以把隨機 IO 變成順序 IO,從而提升查詢效率帚桩;

3亿驾、索引在進(jìn)行分組、排序操作時避免使用臨時表账嚎,從而提升查詢效率莫瞬;

應(yīng)該選擇一種什么樣的數(shù)據(jù)結(jié)構(gòu),才能實現(xiàn)通過索引來實現(xiàn)數(shù)據(jù)的高效檢索呢郭蕉?MySQL 數(shù)據(jù)庫選擇的是 B+ Tree 作為索引的數(shù)據(jù)結(jié)構(gòu)乏悄,下面我們來看看為什么選擇 B+Tree。

2恳不、四種數(shù)據(jù)結(jié)構(gòu)介紹

2.1、二叉查找樹(Binary Search Tree)

二叉搜索樹的特點:左子樹的鍵值小于根的鍵值开呐,右子樹的鍵值大于根的鍵值烟勋。
在這里插入圖片描述
在這里插入圖片描述

從上面的 2 個圖來看规求,同樣是 30 個數(shù)字,插入的數(shù)據(jù)順序不一樣卵惦,二叉樹的結(jié)構(gòu)完全不一樣阻肿,圖 1 里查找 30 需要 2 次檢索的 IO 操作,但是在圖 2 里查找 30 需要 7 次檢索的 IO 操作沮尿,在圖 2 里查找 30 類似于全表掃描丛塌。

此處為什么說是一次檢索就有一次 IO 呢,因為要查找的數(shù)據(jù)在文件里畜疾,需要從文件里讀取出來加載到內(nèi)存里進(jìn)行數(shù)據(jù)比較赴邻,如果相等就返回,如果不相等啡捶,假設(shè)比要查找的數(shù)字大姥敛,需要接著往左邊找;假設(shè)比要查找的數(shù)字小瞎暑,需要接著往右邊找彤敛。

以上可以看出,二叉樹的數(shù)據(jù)檢索取決于數(shù)據(jù)的分布情況了赌,不適合用作索引的數(shù)據(jù)結(jié)構(gòu)墨榄,因為二叉樹的深度太深的話,IO 操作會特變多勿她,查詢效率就會很低袄秩,因此若想二叉樹的查詢效率盡可能高,需要這棵二叉樹是平衡的嫂拴,從而引出新的數(shù)據(jù)結(jié)構(gòu)播揪,平衡二叉樹(Balanced Binary Search Tree)或者完全平衡二叉樹(又叫 AVL 樹)。

2.2筒狠、平衡二叉樹

平衡二叉樹(Balanced Binary Search Tree 樹)在符合二叉查找樹的條件下猪狈,滿足某一個節(jié)點的子節(jié)點的高度差不超過 1,也就是相對平衡辩恼;如果整棵樹的所有節(jié)點的高度差不超過 1 就是完全平衡二叉樹(又叫 AVL 樹)雇庙。
在這里插入圖片描述

樹節(jié)點的數(shù)據(jù)存儲結(jié)構(gòu)示意圖:

在這里插入圖片描述

每個節(jié)點其實就是一個磁盤塊,有 3 部分?jǐn)?shù)據(jù)區(qū)灶伊,一個是關(guān)鍵字:用于存放主鍵或者其他索引的值疆前,一個是數(shù)據(jù)磁盤塊的地址,一個是子節(jié)點的引用聘萨,分別指向父節(jié)點的左子節(jié)點的引用和右子節(jié)點的引用竹椒。

以上面的平衡二叉樹的圖片為例,通過查找關(guān)鍵字為 10 的數(shù)據(jù)記錄米辐,來說明節(jié)點的查找過程說明:

1胸完、先找到節(jié)點 15书释,把節(jié)點 15 加載到內(nèi)存后,與 10 比較赊窥,發(fā)現(xiàn)比 10 大爆惧,那么需要找到 節(jié)點 15 的左子節(jié)點,也就是節(jié)點 8锨能;

2扯再、通過節(jié)點 15 的左子節(jié)點的引用,找到節(jié)點 8址遇,把節(jié)點 8 加載到內(nèi)存后熄阻,與 10 比較,發(fā)現(xiàn)比 10 小傲隶,那么需要找到節(jié)點 8 的右子節(jié)點饺律,也就是節(jié)點 10;

3跺株、通過節(jié)點 8 的右子節(jié)點的引用复濒,找到節(jié)點 10,把節(jié)點 10 加載到內(nèi)存后乒省,與 10 比較巧颈,發(fā)現(xiàn)正好匹配,那么說明要查詢的數(shù)據(jù)就是節(jié)點 10袖扛;

4砸泛、通過節(jié)點 10 的數(shù)據(jù)磁盤地址,找到數(shù)據(jù)區(qū)蛆封,進(jìn)行數(shù)據(jù)的獲取唇礁,返回到客戶端即可。

二叉樹存在數(shù)據(jù)分布不均勻惨篱,出現(xiàn)查詢深度太深盏筐,平衡二叉樹解決了數(shù)據(jù)分布相對平衡的事情,但是用平衡二叉樹作為索引的話還是有問題砸讳,原因主要有兩個:

一個就是數(shù)據(jù)節(jié)點的深度決定了磁盤的 IO 操作次數(shù)琢融,IO 操作非常消耗時間,從上圖可以看出 9 條記錄簿寂,如果查找 30 就需要 4 次 IO 操作漾抬,如果記錄成千上萬,這種 IO 操作是巨大的災(zāi)難常遂。

另外一個就是平衡二叉樹的節(jié)點磁盤塊保存的數(shù)據(jù)量太少纳令,它沒有很好的利用操作系統(tǒng)讀取磁盤 IO 的數(shù)據(jù)交互特性(操作系統(tǒng)去磁盤上讀取的數(shù)據(jù)是 4KB,交互的單位是以頁為單位的),以上的二叉樹數(shù)據(jù)結(jié)構(gòu)一個節(jié)點不可能用滿 4KB 的空間平绩;也沒有利用好磁盤 IO 的預(yù)讀能力(即空間局部性原理)(磁盤預(yù)讀能力就是當(dāng)你一次 IO 讀取到數(shù)據(jù)的頁后坤按,會認(rèn)為你馬上要讀取相鄰的數(shù)據(jù)頁,所以磁盤會多返回幾個頁的數(shù)據(jù)到內(nèi)存)馒过,從而帶來頻繁的 IO 操作。

2.3酗钞、多路平衡查找樹(B-Tree)

多路平衡是指每個節(jié)點可以有多個分支腹忽,也就是可以有多個子節(jié)點,二叉樹就是 2 個子節(jié)點砚作,有幾個子節(jié)點就是幾路窘奏。

多路平衡與二叉平衡相比,可以大大減少樹的深度葫录,從而減少 IO 的操作次數(shù)着裹。

多路平衡查找樹的節(jié)點里的關(guān)鍵字最多有(路數(shù)-1)個,如果用 N 來表示路數(shù)米同,那么關(guān)鍵字的個數(shù)最多就是 N-1 個骇扇。

InnoDB 存儲引擎中有頁(Page)的概念,頁是其磁盤管理的最小單位面粮。InnoDB 存儲引擎中默認(rèn)每個頁的大小為 16KB少孝,可通過參數(shù) innodbpagesize 將頁的大小設(shè)置為 4K、8K熬苍、16K稍走,在 MySQL 中可通過如下命令查看頁的大小: show variables like 'innodb_page_size';

由于 MySQL 數(shù)據(jù)庫里默認(rèn)的一頁是 16KB柴底,因此在數(shù)據(jù)庫設(shè)計的時候要特別注意婿脸,如果一個列的長度太大,該列用作索引時柄驻,占用的空間就大狐树,那么以此列為索引的索引文件的路數(shù)就會減少,從而使樹的深度增加凿歼,也就使 IO 的操作次數(shù)增加褪迟,導(dǎo)致數(shù)據(jù)庫性能下降,這也就是人們常說的創(chuàng)建字段的時候答憔,字段的長度盡量小一點味赃,不要太大的原因。
在這里插入圖片描述

B-Tree 是一個絕對平衡的查找樹虐拓,也就是所有的子節(jié)點都在一個高度上心俗,為了維持樹的絕對平衡,在數(shù)據(jù)插入更新操作時,會通過一些分裂組合的操作來維持城榛,這塊也是比較消耗性能的揪利,這也就是人們常說的索引建立夠用就行,建立索引不易太多的主要原因狠持。因為索引建多了疟位,當(dāng)數(shù)據(jù)插入或者更新的時候,維護(hù)索引的成本也是很大的喘垂。

B-Tree 是為磁盤等外存儲設(shè)備設(shè)計的一種平衡查找樹甜刻,B-Tree 結(jié)構(gòu)的數(shù)據(jù)可以讓系統(tǒng)高效的找到數(shù)據(jù)所在的磁盤塊。關(guān)系型數(shù)據(jù)庫一般都會用 B-Tree 的改進(jìn)版作為索引的數(shù)據(jù)結(jié)構(gòu)正勒。

2.4得院、加強版多路平衡查找樹(B+Tree)

B+Tree 是在 B-Tree 基礎(chǔ)上的一種優(yōu)化,MySQL 數(shù)據(jù)庫的存儲引擎就是用 B+Tree 作為它的索引數(shù)據(jù)結(jié)構(gòu)章贞,MySQL 數(shù)據(jù)庫有幾路取決于索引的字段長度祥绞。
在這里插入圖片描述

在 B+Tree 中,所做的優(yōu)化是:所有數(shù)據(jù)記錄節(jié)點都是按照鍵值大小順序存放在葉子節(jié)點上鸭限,而非葉子節(jié)點上只存儲關(guān)鍵字和子節(jié)點的引用蜕径,非葉子節(jié)點不存數(shù)據(jù)塊的磁盤地址;這樣可以大大加大每個節(jié)點存儲的 key 值數(shù)量里覆,降低 B+Tree 的高深度丧荐。

同時最底層的葉子節(jié)點之間都有一個指針,把上一個節(jié)點的數(shù)據(jù)塊里的最后一個地址指向到下一個節(jié)點的數(shù)據(jù)塊里的第一個地址喧枷,這樣就可以使數(shù)據(jù)庫形成一個有序鏈表虹统,因此可以做到順序 IO 操作。

由于以上的特點隧甚,B+Tree 的全表掃描的能力更強车荔,因為數(shù)據(jù)是放到葉子節(jié)點上的,只需要讀取葉子節(jié)點就可以了戚扳;同時 B+Tree 的排序能力更強忧便,B+Tree 的查詢能力更穩(wěn)定,每次都需要檢索到葉子節(jié)點才能拿到數(shù)據(jù)帽借。

3珠增、MySQL 中 B+Tree 索引的實現(xiàn)方式

3.1、Myisam 存儲引擎中的實現(xiàn)

.frm 表定義文件:每一個存儲引擎都有這個文件

.myd 數(shù)據(jù)文件:d 代表 data砍艾,數(shù)據(jù)庫表中的數(shù)據(jù)保存在這個文件

.myi 索引文件:i 代表 Index蒂教,索引保存在這個文件

Myisam 引擎的數(shù)據(jù)文件與索引文件是分開的,在.myi 索引文件中無論是主鍵索引還是輔助索引脆荷,其葉子節(jié)點保存的是.myd 數(shù)據(jù)文件中的數(shù)據(jù)行的地址指針凝垛,因此 Myisam 引擎獲取數(shù)據(jù)記錄的過程是先從索引文件中拿到數(shù)據(jù)區(qū)的地址懊悯,然后再去數(shù)據(jù)文件中獲取對應(yīng)地址的數(shù)據(jù)返回給客戶端。

3.2梦皮、Innodb 存儲引擎中的實現(xiàn)

.frm 表定義文件:每一個存儲引擎都有這個文件

.ibd 數(shù)據(jù)文件:數(shù)據(jù)庫表中的數(shù)據(jù)保存在這個文件

在 InnoDB 存儲引擎里炭分,它是以主鍵為索引來組織數(shù)據(jù)的存儲的,所以索引文件和數(shù)據(jù)文件是同一個文件剑肯,都在 .ibd 文件里面捧毛。

Innodb 以主鍵為索引來組織數(shù)據(jù)的存儲,如果沒有指定主鍵让网,那么 InnoDB 會默認(rèn)增加主鍵索引岖妄,同時,葉子節(jié)點存放的是整張表的行記錄數(shù)據(jù)寂祥,因為主鍵對應(yīng)的行所有的字段都在葉子節(jié)點上存在,而且索引鍵值的邏輯順序跟數(shù)據(jù)庫表中的數(shù)據(jù)行內(nèi)容存儲順序是一致七兜,所以這種主鍵索引也叫聚集索引丸凭。

Innodb 的輔助索引與聚集索引的區(qū)別在于輔助索引的葉子節(jié)點并不包含行記錄的全部數(shù)據(jù),而是存儲相應(yīng)行數(shù)據(jù)的聚集索引鍵聚集索引鍵(即主鍵的值),當(dāng)通過輔助索引來查詢數(shù)據(jù)時腕铸,InnoDB 存儲引擎會遍歷輔助索引找到主鍵惜犀,然后再通過主鍵在聚集索引中找到完整的行記錄數(shù)據(jù)。

InnoDB 會默認(rèn)增加主鍵索引的規(guī)則: 1狠裹、如果定義了主鍵(PRIMARY KEY)虽界,那么 InnoDB 會選擇主鍵作為聚集索引; 2涛菠、如果沒有定義主鍵莉御,那么 InnoDB 會選擇第一個不包含有 NULL 值的唯一索引作為主鍵索引; 3俗冻、如果唯一索引也沒有定義礁叔,那么 InnoDB 會選擇內(nèi)置 6 個字節(jié)的 ROWID 作為默認(rèn)的聚集索引,采用主鍵遞增的策略生成迄薄。

Innodb 引擎的聚集索引把行記錄數(shù)據(jù)與主鍵全部存起來的原因是考慮到用主鍵做查詢的情況比較多琅关,所以把所有的行記錄聚集起來放到主鍵的葉子節(jié)點上。

Innodb 引擎的輔助索引用主鍵值而不用地址表示讥蔽,主要原因是當(dāng)數(shù)據(jù)變化的時候涣易,如果用的是主鍵,不是地址的話冶伞,不用再維護(hù)輔助索引了新症。

五、深入了解數(shù)據(jù)庫的索引

1碰缔、索引的幾個概念

單列索引: 索引節(jié)點中的關(guān)鍵字是一個列的內(nèi)容账劲,也叫普通索引,比如:用身份證號做索引,用手機號做索引瀑焦。

聯(lián)合索引: 索引節(jié)點中的關(guān)鍵字是多個列的內(nèi)容腌且,經(jīng)常在需要用多個字段查詢的時候用到。比如:用手機號+時間做索引榛瓮,或者手機號+時間+狀態(tài)做索引铺董;也就是說單列索引是特殊的聯(lián)合索引。

唯一索引: 索引列的值必須唯一禀晓,但允許有空值精续;如果是聯(lián)合索引,則列值的組合必須唯一粹懒。

主鍵索引: 當(dāng)給這一張表指定主鍵以后重付,那么這個主鍵就會變成一個主鍵索引,主鍵索引是唯一性索引凫乖,唯一性索引并不一定就是主鍵确垫。

聚集索引(聚簇索引): 聚集索引的 B+Tree 中的葉子節(jié)點存放的是整張表的行記錄數(shù)據(jù),而且索引鍵值的邏輯順序跟數(shù)據(jù)庫表中的數(shù)據(jù)行內(nèi)容存儲順序是一致帽芽,輔助索引與聚集索引的區(qū)別在于輔助索引的葉子節(jié)點并不包含行記錄的全部數(shù)據(jù)删掀,而是存儲相應(yīng)行數(shù)據(jù)的聚集索引鍵,即主鍵的值导街。

輔助索引: 輔助索引也叫非聚集索引披泪,也就是非主鍵索引。

回表掃描: 在 InnoDB 中輔助索引里存放的是主鍵值搬瑰,假設(shè)查詢條件不是主鍵而是輔助索引款票,那么首先需要從輔助索引里找到對應(yīng)的主鍵值,然后從主鍵索引里找到該主鍵值對應(yīng)的數(shù)據(jù)記錄行泽论,這個過程就叫做回表掃描徽职,因為這個過程比基于主鍵索引的查詢多掃描了一棵輔助索引樹,這個過程就叫回表掃描佩厚,意思就是從輔助索引樹里找一圈姆钉,然后再回到主鍵索引里找一圈。

覆蓋索引: 在輔助索引里面抄瓦,不管是單列索引還是聯(lián)合索引潮瓶,如果查詢的數(shù)據(jù)列只用從索引節(jié)點中的關(guān)鍵字就能夠取得,不必從數(shù)據(jù)區(qū)中讀取主鍵值钙姊,再回到主鍵索引查詢記錄行毯辅,這時候使用的索引就叫做覆蓋索引,這樣就避免了回表掃描煞额,所以說思恐,用到覆蓋索引的查詢效率會高一些沾谜,原因就是不用進(jìn)行回表掃描操作,IO 操作次數(shù)減少了胀莹。同時覆蓋索引也可以減少數(shù)據(jù)庫 IO基跑,將隨機 IO 變?yōu)轫樞?IO,因此提高數(shù)據(jù)的查詢效率描焰。

了解了覆蓋索引的概念媳否,我們就能知道為什么數(shù)據(jù)庫開發(fā)一般要求不要用 select * 查詢,除了 select * 查詢需要返回的字段值多荆秦,占用空間以外篱竭,更重要的原因就是,如果業(yè)務(wù)需求只需要查詢索引列的時候步绸,直接查索引字段會直接從索引文件返回內(nèi)容掺逼,而不需要回表掃描,這樣就大大提升了查詢的性能瓤介。

2坪圾、索引的創(chuàng)建原則

在實際開發(fā)過程中,一般人們存在一個誤區(qū)惑朦,就是查詢效率低,我們創(chuàng)建索引解決就行了漓概,也有人把“在經(jīng)常使用的查詢條件上都建立索引“作為解決查詢緩慢的法則漾月,其實通過索引數(shù)據(jù)結(jié)構(gòu)的學(xué)習(xí),大家應(yīng)該能有體會胃珍,索引不是越多越好梁肿,太多的索引反而會影響數(shù)據(jù)庫的性能。

下面介紹索引創(chuàng)建的 3 個原則:

2.1觅彰、最少空間原則

最少空間指的是列的長度小吩蔑,長度越小的列,B+Tree 的路數(shù)就會越多填抬,IO 檢索的次數(shù)就會越少烛芬,查詢的效率就會越高,也就是說索引的效果越好飒责。如果不理解赘娄,請再看一下索引的數(shù)據(jù)結(jié)構(gòu)部分的內(nèi)容。

2.2宏蛉、高離散度列原則

數(shù)據(jù)表中列的離散度公式:count(distinct(列名稱)) / count(*)佛玄,也就是列的所有不相同的值和所有數(shù)據(jù)記錄總行數(shù)的比洒闸,如果列的所有不相同的值和數(shù)據(jù)記錄總行數(shù)約接近,那么列的離散度越好屋确,簡單來說,如果列的重復(fù)值越多柒凉,離散度越低,重復(fù)值越少,離散度越就越高隐砸。

這也就是大家都了解的不要再性別字段上建立索引的主要原因,因為性別字段列的值除了男就是女西采,列的散型太差凰萨,建立索引起不到效果,查詢優(yōu)化器選擇執(zhí)行計劃可能覺得走這樣的索引還不如走全表掃描械馆。

因此我們在創(chuàng)建索引的時候盡量選擇離散度高的列胖眷,也就是選擇列的值幾乎沒有重復(fù)的列做索引效果最好。

2.3霹崎、最左匹配原則

最左匹配原則一般用于聯(lián)合索引中珊搀,聯(lián)合索引在 B+Tree 中是復(fù)合的數(shù)據(jù)結(jié)構(gòu),最左匹配原則就是聯(lián)合索引的檢索比對是從左往右匹配的尾菇,它是按照從左到右的順序來建立搜索樹的境析。

假如一張表用手機號和時間聯(lián)合索引【phone,time】派诬,沒有建立 time 的單列索引劳淆。

那么聯(lián)合索引【phone,time】(phone 在左邊默赂,time 在右邊)沛鸵,就表示:phone 是有序的,time 是無序的缆八;當(dāng) phone 相等的時候曲掰,time 才是有序的。

這個時候我們使用 phone 和 time 作為查詢條件的時候奈辰,B+Tree 會優(yōu)先比較 phone 來確定下一步應(yīng)該搜索的方向栏妖,往左還是往右;如果 phone 相同的時候再比較 time 奖恰;但是如果查詢條件只有 time吊趾,那么就不知道第一步應(yīng)該查哪個節(jié)點,因為建立搜索樹的時候 phone 是在左邊瑟啃,所以用 time 查詢就不會用到索引趾徽。

如果用 phone 作為查詢條件,是否可以用到索引呢翰守,答案是肯定的孵奶,因為 phone 在聯(lián)合索引的左邊,所以用 phone 獨立查詢蜡峰,按照最左匹配原則是可以用到索引的了袁。

從最左匹配原則我們就能發(fā)現(xiàn)朗恳,如果創(chuàng)建了聯(lián)合索引【phone,time】载绿,那么就沒有必要再去創(chuàng)建單列索引【phone】了粥诫,但是如果有用 time 作為查詢條件的情況,就需要創(chuàng)建 time 列的索引【time】崭庸。

3怀浆、索引使用的幾個注意事項

  • 在 where 判斷 order 排序和 join(on)的字段上創(chuàng)建索引

  • 索引字段最好不要為 null 值

  • 索引列的長度能少則少

  • 索引不是查詢字段都要建立索引,也不是越多越好

  • 注意聯(lián)合索引的使用最左匹配原則

  • 選擇索引要選離散度高的列

  • 聯(lián)合索引里最左的列怕享,就不要創(chuàng)建單列索引了执赡,浪費空間不說,還增加了更新操作的索引維護(hù)成本

  • 頻繁更新的值函筋,不要作為主鍵或者索引

  • 索引列上避免使用函數(shù)(replace沙合、substr、concat跌帐、sum)和運算

  • 字符串查詢一定要加引號

  • like 條件中前面帶 %首懈,同時要保證 % 前面的內(nèi)容離散度要高

  • 避免使用 NOT IN 、<>谨敛、NOT LIKE 等負(fù)向判斷

  • 可以使用 limit 關(guān)鍵字進(jìn)行查詢記錄限制

六究履、深入了解數(shù)據(jù)庫的事務(wù)

1、什么是事務(wù)

事務(wù)是數(shù)據(jù)庫管理系統(tǒng)(DBMS)執(zhí)行過程中的一個邏輯單位脸狸,由一個有限的數(shù)據(jù)庫操作序列構(gòu)成最仑,事務(wù)是不可以再分的最小的數(shù)據(jù)庫工作單元,它包含了一個或者多個 DML 語句肥惭,比如 insert、update紊搪、delete蜜葱。

InnoDB 存儲引擎是支持事務(wù)的,這也是它成為默認(rèn)的存儲引擎的一個重要原因耀石。

最常見的事務(wù)操作就是金融系統(tǒng)的銀行轉(zhuǎn)賬場景牵囤,簡單的說 A 賬戶轉(zhuǎn)出多少金額給 B 賬戶,那么 B 賬戶必須完成對應(yīng)金額的增加滞伟,這個轉(zhuǎn)賬業(yè)務(wù)才算成功揭鳞,否則就出大問題了。

再比如電商系統(tǒng)的下訂單場景梆奈,訂單表和庫存表一定是要在一個事務(wù)里完成的野崇。

事務(wù)里的操作,要么同時成功亩钟,要么同時失敗乓梨,這樣才能保證事務(wù)操作的一致性鳖轰。

2、事務(wù)的四大特性

事務(wù)的四大特性:ACID扶镀。

2.1蕴侣、原子性(Atomicity)

原子性,又叫不可分割性臭觉,它是指一個事務(wù)(transaction)中的所有操作昆雀,要么全部成功,要么全部失敗蝠筑。如果事務(wù)在執(zhí)行過程中發(fā)生錯誤狞膘,就會被回滾(rollback)到事務(wù)執(zhí)行之前的狀態(tài),也就是說要返回原樣菱肖,就像這個事務(wù)從來沒有執(zhí)行過一樣客冈。 原子性的回滾操作在 InnoDB 里面是通過 undolog 來實現(xiàn)的,它記錄了數(shù)據(jù)修改之前的值(邏輯日志)稳强,一旦發(fā)生異常场仲,就可以用 undo log 來實現(xiàn)回滾操作。

2.2退疫、一致性(Consistent)

一致性渠缕,指的是在事務(wù)執(zhí)行前后,數(shù)據(jù)庫的完整性約束沒有被破壞褒繁,事務(wù)執(zhí)行的前后都是合法的數(shù)據(jù)狀態(tài)亦鳞。比如主鍵必須是唯一的,字段長度符合要求等棒坏,也不會因為系統(tǒng)出現(xiàn)異常等原因?qū)е聰?shù)據(jù)前后的狀態(tài)不一致燕差。

除了數(shù)據(jù)庫自身的完整性約束,我們在寫代碼的時候坝冕,還要滿足用戶自定義的完整性徒探。比如:A 賬戶要給 B 賬戶轉(zhuǎn)賬 10000 元,如果 A 賬戶余額減少 10000 元喂窟,B 賬戶余額只增加了 1000 元测暗,這個時候兩個 sql 操作都可以成功,因為它是滿足原子性的磨澡,但是明顯存在業(yè)務(wù)問題碗啄;假設(shè) A 賬戶里沒有 10000 元,那么也是不能夠執(zhí)行轉(zhuǎn)賬操作的稳摄,一般用戶自定義的完整性需要在代碼中做好判斷和控制稚字。

2.3、隔離性(Isolation)

隔離性可以防止多個事務(wù)并發(fā)的讀寫操作時厦酬,由于交叉執(zhí)行而導(dǎo)致數(shù)據(jù)的不一致尉共。因為數(shù)據(jù)庫允許多個并發(fā)事務(wù)同時去讀寫或者修改數(shù)據(jù)庫的同一張表或者同一行數(shù)據(jù)褒傅,如果不加控制,數(shù)據(jù)一定會不一致袄友。隔離性就是指多個并發(fā)事務(wù)對同一張表或者同一行數(shù)據(jù)的讀寫操作殿托,應(yīng)該是互相不干擾的。主要是指一個事務(wù)要操作的數(shù)據(jù)在提交之前剧蚣,對其他事務(wù)應(yīng)該是不可見的支竹,從而可以保證業(yè)務(wù)數(shù)據(jù)的一致性。

數(shù)據(jù)庫的隔離性是通過事務(wù)的隔離級別來實現(xiàn)的鸠按,這塊在后面介紹礼搁。

2.4、持久性(Durable)

持久性是指事務(wù)處理(對數(shù)據(jù)庫的任意的增刪改操作)結(jié)束后目尖,對數(shù)據(jù)的修改就是永久的馒吴,即便數(shù)據(jù)庫宕機也不會丟失(數(shù)據(jù)庫的磁盤文件損壞除外)。

數(shù)據(jù)庫宕機后的恢復(fù)是通過 redolog 來實現(xiàn)的數(shù)據(jù)持久性恢復(fù)瑟曲,數(shù)據(jù)庫在操作數(shù)據(jù)的時候饮戳,會先寫到內(nèi)存的 buffer pool 里面,同時記錄 redo log洞拨。如果在寫到磁盤之前出現(xiàn)異常扯罐,那么重啟后就可以讀取 redo log 的內(nèi)容,然后再寫入到磁盤烦衣,從而保證數(shù)據(jù)的持久性歹河。

其實事務(wù)的原子性、隔離性花吟、持久性秸歧,最后都是為了實現(xiàn)事務(wù)的最終一致性。

3衅澈、MySQL 如何開啟事務(wù)

1键菱、自動開啟事務(wù),自動提交或者回滾事務(wù)

InnoDB 有一個 autocommit 的參數(shù)(分成兩個級別矾麻, session 級別和 global 級別)纱耻。

show variables like 'autocommit';

它的默認(rèn)值是 ON芭梯,如果 autocommit 值是 true/on 的話险耀,我們在操作數(shù)據(jù)的時候,會自動開啟一個事務(wù)玖喘,和自動提交事務(wù)甩牺;如果把 autocommit 設(shè)置成 false/off,那么數(shù)據(jù)庫的事務(wù)就需要我們手動地去開啟和手動地去結(jié)束累奈。

2贬派、手動開啟事務(wù)急但,手動提交或者回滾

手動開啟事務(wù)可以用 begin,也可以用 start transaction搞乏;結(jié)束一個事務(wù)也有兩種方式波桩,可以用 commit 提交一個事務(wù),也可以用 rollback 回滾事務(wù)请敦。

4镐躲、了解并發(fā)給數(shù)據(jù)庫帶來的問題

下面我們來分析一下,假設(shè)沒有事務(wù)的隔離性侍筛,當(dāng)兩個事務(wù)并發(fā)地去操作數(shù)據(jù)庫的表或者行的時候萤皂,那么會產(chǎn)生什么問題?

  • 讀臟數(shù)據(jù): A 事務(wù)修改了一個數(shù)據(jù)(假設(shè) A 從 1 改為 2)匣椰,B 事務(wù)讀取 A 事務(wù)修改后的數(shù)據(jù)(B 讀取到了 2)裆熙,但由于某種原因 A 事務(wù)撤銷了事務(wù)(這個數(shù)據(jù)回滾到 1),此時導(dǎo)致 B 事務(wù)讀取到的數(shù)據(jù)不正確(B 認(rèn)為數(shù)據(jù)是 2)禽笑,這就表示 B 事務(wù)讀取到了臟數(shù)據(jù)入录,一般稱為臟讀。

  • 不可重復(fù)讀 A 事務(wù)讀取數(shù)據(jù)后(假設(shè) A 讀到了 1)蒲每,B 事務(wù)執(zhí)行更新操作(B 把 1 改成了 2)纷跛,然后 B 事務(wù)提交(此時數(shù)據(jù)的值為 2);然后 A 事務(wù)再次讀取數(shù)據(jù)(A 讀到了 2)邀杏,也就是說 A 事務(wù)兩次讀取操作得到了 2 個結(jié)果(第一次是 1贫奠,第二次是 2)。說明在一個事務(wù)里對同一個數(shù)據(jù)讀取望蜡,得到的值不一致唤崭,后面的讀操作獲得了其他它事務(wù)提交的結(jié)果,這就表示 A 事務(wù)不可重復(fù)度脖律。

  • 幻讀 A 事務(wù)讀取價格小于 10 的產(chǎn)品數(shù)據(jù)(假設(shè) A 讀到了 100 條數(shù)據(jù))谢肾,B 事務(wù)往產(chǎn)品表里插了一條價格小于 10 的產(chǎn)品,然后 B 事務(wù)提交(此時價格小于 10 的產(chǎn)品有 101 條)小泉;然后 A 事務(wù)再次讀取價格小于 10 的產(chǎn)品數(shù)據(jù)(A 讀到了 101 條數(shù)據(jù))芦疏,也就是說 A 事務(wù)讀取到了 B 事務(wù)新增的記錄(第一次是 100 條,第二次是 101 條)微姊。這就表示 A 事務(wù)發(fā)生了幻讀酸茴。

    幻讀與不可重復(fù)讀的區(qū)別: 不可重復(fù)讀是由其他事務(wù)的修改操作引發(fā)的讀不一致,幻讀是由于其他事務(wù)新增或者刪除記錄引發(fā)的讀不一致兢交。從結(jié)果上看薪捍,不可重復(fù)讀和幻讀差不多。但從控制的角度來看, 兩者的區(qū)別就比較大。 對于前者, 只需要鎖住滿足條件的記錄酪穿。 對于后者, 要鎖住滿足條件及其相近的記錄

以上事務(wù)并發(fā)帶來的三大問題凳干,無論是臟讀,還是不可重復(fù)讀被济,或者是幻讀救赐,它們都是數(shù)據(jù)庫的讀一致性的問題,都是在一個事務(wù)里面前后兩次讀取出現(xiàn)了不一致的情況只磷。

5净响、MySQL 事務(wù)的隔離級別

針對并發(fā)給數(shù)據(jù)庫帶來的三個問題讀一致性的問題,SQL92 標(biāo)準(zhǔn)為各個數(shù)據(jù)庫廠商提供一定的事務(wù)隔離級別喳瓣,來解決事務(wù)并發(fā)的問題馋贤。

還有 36% 的精彩內(nèi)容
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
支付 ¥19.98 繼續(xù)閱讀
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市畏陕,隨后出現(xiàn)的幾起案子配乓,更是在濱河造成了極大的恐慌,老刑警劉巖惠毁,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件犹芹,死亡現(xiàn)場離奇詭異,居然都是意外死亡鞠绰,警方通過查閱死者的電腦和手機腰埂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來蜈膨,“玉大人屿笼,你說我怎么就攤上這事∥涛。” “怎么了驴一?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵,是天一觀的道長灶壶。 經(jīng)常有香客問我肝断,道長,這世上最難降的妖魔是什么驰凛? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任胸懈,我火速辦了婚禮,結(jié)果婚禮上恰响,老公的妹妹穿的比我還像新娘趣钱。我一直安慰自己,他們只是感情好渔隶,可當(dāng)我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布羔挡。 她就那樣靜靜地躺著,像睡著了一般间唉。 火紅的嫁衣襯著肌膚如雪绞灼。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天呈野,我揣著相機與錄音低矮,去河邊找鬼。 笑死被冒,一個胖子當(dāng)著我的面吹牛军掂,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播昨悼,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼蝗锥,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了率触?” 一聲冷哼從身側(cè)響起终议,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎葱蝗,沒想到半個月后穴张,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡两曼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年皂甘,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片悼凑。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡偿枕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出户辫,到底是詐尸還是另有隱情益老,我是刑警寧澤,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布寸莫,位于F島的核電站捺萌,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏膘茎。R本人自食惡果不足惜桃纯,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望披坏。 院中可真熱鬧态坦,春花似錦、人聲如沸棒拂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至谜诫,卻和暖如春漾峡,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背喻旷。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工生逸, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人且预。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓槽袄,卻偏偏與公主長得像,于是被迫代替她去往敵國和親锋谐。 傳聞我的和親對象是個殘疾皇子遍尺,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內(nèi)容