mysql索引引擎範式事務總結

三範式

origin link
refer link
一範式:每列不可分。【部門角色字段(銷售部實習生)就應該切分爲部門字段(銷售部)和角色字段(實習生)】
二範式:每列與主鍵相關(直接相關或者間接相關)一個表只描述一件事情。一個數據庫表中只能保存一種數據(一張表對應一個pojo對象)訂單表和商品表不能設計在一張表裏,應該分開兩個表,再加一個多對多的商品id和訂單id關聯表。(拆多表)【多對多關係應該拆表,使用中間表來關聯(解耦)多對多】
在這裏插入圖片描述

三範式:每列與主鍵直接相關每個屬性都跟主鍵有直接關係而不是間接關係。【消除傳遞依賴】
用戶名/用戶電話是通過用戶id和訂單id間接關聯(外鍵關聯來解耦 一對多),所以
在這裏插入圖片描述

比如Student表(學號,姓名,年齡,性別,所在院校,院校地址,院校電話)
這樣一個表結構,就存在上述關係。 學號–> 所在院校 --> (院校地址,院校電話)
這樣的表結構,我們應該拆開來,如下。(學號,姓名,年齡,性別,所在院校)–(所在院校,院校地址,院校電話)

總結:三大範式只是一般設計數據庫的基本理念,可以建立冗餘較小、結構合理的數據庫。如果有特殊情況,當然要特殊對待,數據庫設計最重要的是看需求跟性能,需求>性能>表結構。所以不能一味的去追求範式建立數據庫。

存儲引擎

在這裏插入圖片描述
\color{cyan}{存儲引擎是基於表的,而不是數據庫}
【Innodb,MYISAM,MEMORY】【ARCHIVE,BLACKHOLE,CSV,MRG_MYISAM,PERFORMANCE_SCHEMA】

  • Innodb\color{red}{Innodb}
    MySQL5.5以及之後的版本採用innodb作爲默認的存儲引擎,
    主要特點
    支持行級鎖
    支持外鍵約束
    完備的事務機制,實現了四種隔離級別
    可靠性號,崩潰後修復能力較高
    文件格式
    .frm(存儲表定義)
    共享表空間文件:ibdata1
    私有表空間文件:表名.ibd
    redo log文件
    適用場景 :【數據修改頻繁,對事務特性要求比較高(如金融系統),需要支持併發處理能力的系統。】

  • MYISAM\color{red}{MYISAM}
    MySQL5.5以前採用MYISAM作爲默認的存儲引擎
    主要特點
    比較強調讀取效率,查詢速度較快
    磁盤空間佔用少
    只支持表級鎖,併發能力較差
    不支持事務,災難恢復能力較差
    文件格式
    .frm(存儲表定義)
    MYD(MYData,存儲數據)
    MYI(MYIndex,存儲索引)
    適用場景:【數據很少更新,一次插入,多次讀取的業務場景。】

  • MEMORY\color{red}{MEMORY}
    類似於內存緩存,表結構的定義存在磁盤上(frm文件),實際數據是存儲在內存中
    主要特點
    響應速度快
    表級鎖,頻繁更新數據可能會造成併發瓶頸
    不支持可變字段(但可以藉助verchar實現文本存儲)
    數據可靠性很差,機器或MySQL服務器重啓後,就會丟失
    需要機器有足夠的內存
    適用場景:【數據量不大,需要被頻繁的訪問,而且數據丟失不會對業務產生比較嚴重的影響。】

  • ARCHIVE\color{red}{ARCHIVE}
    【檔案文件】【用於數據歸檔;它的壓縮比非常的高,存儲空間大概是innodb的10-15分之一所以它用來存儲歷史數據非常的適合,由於它不支持索引同時也不能緩存索引和數據,由於高壓縮和快速插入的特點Archive非常適合作爲日誌表的存儲引擎,但是前提是不經常對該表進行查詢操作。archive存儲引擎支持insert、replace和select操作,但是不支持update和delete。】

  • BLACKHOLE\color{red}{BLACKHOLE}
    【黑洞引擎,寫入的任何數據都會消失,用於記錄binlog做複製的中繼存儲!比如一個表test的引擎是BlackHole,任何對這個表的insert都將丟失,
    對它的select永遠返回空集,對應的數據目錄下只有一個test.frm文件,且沒有其他文件與之關聯【適用場景:雖然其不保存數據,但對數據庫的操作仍舊記錄在binlog日誌中。
    這就帶來一個好處,可以將其作爲主從複製的中介,將原來從主庫中同步的操作變爲從作爲中介的BlackHole引擎數據庫中同步。1.作爲僞主庫分擔主庫負擔;2.作爲binlog日誌收集器refer link】】

  • CSV\color{red}{CSV}
    【數據以文本方式存儲在文件中,可對齊直接進行編輯
    【適合做爲數據交換的中間表
    如,A表 與 B表需要進行數據交換,那麼 A表會先將數據導入 CSV 文件中,然後 CSV 文件再將數據導入 B表。】 適合做爲數據交換的中間表(能夠在服務器運行的時候,拷貝和拷出文件,可以將電子表格存儲爲CSV文件再拷貝到MySQL數據目錄下,就能夠在數據庫中打開和使用。同樣,如果將數據寫入到CSV文件數據表中,其它web程序也可以迅速讀取到數據。】

  • MRGMYISAM\color{red}{MRG_MYISAM}
    (合併MYISAM引擎)【是一個相同的可以被當作一個來用的MyISAM表的集合。使用它來實現分表操作https://www.cnblogs.com/datastudy/p/6025462.html
    把幾張結構完全相同的表的數據合併到一張結構完全相同的表裏面】

  • PERFORMANCESCHEMA\color{red}{PERFORMANCE_SCHEMA}
    【性能模式】【主要用於收集數據庫服務器性能參數。MySQL用戶是不能創建存儲引擎爲PERFORMANCE_SCHEMA的表
    performance_schema提供以下功能:
    1.提供進程等待的詳細信息,包括鎖、互斥變量、zd文件信息;
    2.保存歷史的事件彙總信息,爲提供MySQL服務器性能版做出詳細的權判斷;
    3.對於新增和刪除監控事件點都非常容易,並可以隨意改變mysql服務器的監控週期,例如(CYCLE、MICROSECOND)
    通過以上得到的信息,DBA能夠較明細得了解性能降低可能是由於哪些瓶頸?
    l performance_schema功能開啓和部分表功能
    Performance的開啓很簡單,在my.cnf中[mysqld]加入performanc_schema,檢查性能數據庫是否啓動的命令:
    SHOW VARIABLES LIKE ‘performance_schema’;
    若是返回的 值爲ON,則說明性能數據庫正常開啓狀態。】

more refer link

mysql架構及組件

在這裏插入圖片描述
在這裏插入圖片描述
第1層【連接層】的各種服務並非MySQL 獨有。它們是許多基於網絡的客戶端/服務((Client/server))工具或務器都需要的服務,比如連接處理、授權認證、安全

第2層【服務層】值得關注。它包括了MySQL 的大多數核心內容,比如查詢解析、分析、優化、緩存及所有內建函數(如日期、時間、數學和加密函數等)的代碼。各種存儲引擎提供的功能也集中在這層,如存儲過程、觸發器,視圖等。

第3層【引擎層】包含了存儲引擎,存儲引擎負責存儲和提取所有存放在MySQL 中的數據,和GNU/Linux 下的各種文件系統一樣,每個存儲引擎都有自己的優勢和劣勢。服務器通過存儲引擎API(( StorageEngine AP )與引擎進行通信。該接口隱藏了存儲引擎之間的區別,使它們在查詢層上是透明的。AP包含了幾十個底層函數,用來執行相關操作,如“開始一個事務”,“提取一行擁有某主鍵的數據”等等。存儲引擎不會進行SQL解析(注1)(( Parse),也不會互相通信,它們只是簡單地響應服務器的請求

第4層 【存儲層】數據存儲層,主要是將數據存儲在運行於裸設備的文件系統之上,並完成與存儲引擎的交互。

連接詞組件
管理服務和工具組件
sql接口組件
查詢分析器組件
優化器組件
緩衝組件
插件式存儲引擎

innodb存儲引擎

innodb的四大特性

插入緩存,兩次寫,自適應哈希索引,異步IO,刷新臨近頁
插入緩存insert buffer 給innodb帶來了性能上的提升,兩次寫doublewrite給innodb存儲引擎帶來了數據頁的可靠

這裏可以對比jvm來理解學習
sql(編譯優化)---- java(編譯優化)
innodb(磁盤io進行數據加載)-- jvm(類加載)

innodb,最核心的功能就是:將磁盤中的數據加載到內存中來,將內存中的數據寫入到磁盤中去

索引,事務,鎖,日誌文件,表文件等功能都由innodb提供實現,sql語句只是去調用存儲引擎提供的api而已。

mysql技術內幕–innodb存儲引擎(內容概覽–腦圖圖解)

innodb引擎工作過程

對innodb引擎而言:對於建立了索引的字段(引擎會創建索引文件在磁盤中,當數據庫用到索引時,會將這些索引文件讀入內存,建立了索引的字段的數據就會以b+樹的形式存放在內存中)當查詢時,就能夠進行快速的查找了。
按頁加載,使用LRU淘汰機制…
這些過程都有一個線程,負責將這些操作記錄寫入到重做日誌(記錄了對於innodb存儲引擎的事務日誌)中
在innodb,存儲引擎中,主鍵是行的唯一標識符,通常應用程序中行記錄的,插入順序是按照,主鍵遞增的順序進行插入的
現在的innodb使用的是內核級別的nio,即native aio,在innodb存儲引擎中,read ahead方式的讀取都是通過aio實現,髒頁的刷新(即磁盤的寫入操作)全部由aio完成。
引擎會對行加鎖,操作緩衝池中的列表增加,刪除,移動,列表中的元素,爲了保證一致性,也會有鎖的介入

mysql中—lock與latch

這裏還要區分鎖中容易令人混淆的概念lock與latch 。在數據庫中,lock與latch 都可以被稱爲“鎖”。但是兩者有着截然不同的含義,本章主要關注的是lock

latch一般稱爲閂鎖(輕量級的鎖),因爲其要求鎖定的時間必須非常短。若持續的時間長,則應用的性能會非常差。在InnoDB 存儲引擎中,latch 又可以分爲mutex (互斥量)和rwlock (讀寫鎖)。其目的是用來保證併發線程操作臨界資源的正確性,並且通常沒有死鎖檢測的機制。

lock的對象是事務,用來鎖定的是數據庫中的對象,如表、頁、行。並且一般lock的對象僅在事務commit 或rollback 後進行釋放(不同事務隔離級別釋放的時間可能不同)。此外,lock,正如在大多數數據庫中一樣,是有死鎖機制的。表6-1顯示了lock與atch的不同。

sql執行原理

Sql語句的執行原理-MySQL

  1. 應用程序把查詢SQL語句發送給服務器端執行
  2. 查詢緩存,如果命中(緩存中有),則直接從緩存中拿到結果並返回給客戶端,否則就進入下一步
  3. 查詢優化處理,生成執行計劃【這個階段包括:解析SQL、預處理、優化SQL執行計劃【查詢優化器會自動判斷是否使用索引…最終選擇執行成本最低的執行計劃】,其中任何一個階段出錯都會導致查詢進行不下去。】
  4. Mysql根據相應的執行計劃(數據結構)完成整個查詢【這一步由存儲引擎負責完成】
  5. 將查詢結果返回客戶端【如果查詢可以緩存,Mysql在這個階段也會將結果放到查詢緩存中。】

索引原理

如果表中一條記錄佔用磁盤1kb字節的話,對其中一個10個字節的字段建立索引,那麼該記錄對應的索引塊的大小隻有10個字節。瞭解到數據庫中最小的空間單元是頁,一個頁在磁盤上佔用16kb,那麼這個頁就可以記錄16條字段記錄,可以存儲800條索引。如果我們要從8000條記錄的表中檢索符合某個條件記錄的話,如果沒有索引的話,需要遍歷8000條1000字節/8k=1000個頁面。如果有索引的話,則查詢8000條10字節/8k=10個頁面就可以了

在這裏插入圖片描述
0x07,0x56這些是執行數據34,77的物理地址的指針
select * from t2 where col2=89,需要查找6次。假設mysql按頁從磁盤中加載數據到內存。一頁能存一行數據 ,則需要6次io才能查詢到結果。假設對col2字段建立了二叉搜索樹的結構,則2次就可以找到數據。及2次io解決問題

打個比方:沒有建立索引:
一本厚厚的字典(假如有1000頁),當你想查找cool這個單詞時,你就需要從頭到尾一頁一頁的去查找這個單詞,你需要查找1000次。
建立索引:(按照a到z的順序對數據排序)
通過二分查找,迅速從a到z裏面找到c,然後再按照c 的next指針找下去,就能很快找到cool

索引問題清單

  1. mysql頁文件爲何默認16K

假設我們一行數據大小爲1K,那麼一頁就能存16條數據,也就是一個葉子節點能存16條數據;再看非葉子節點,假設主鍵ID爲bigint 類型,那麼長度爲8B,指針大小在Innodbi 源碼中爲6B,一共就是14B,那麼一頁裏就可以存儲16K/14=1170個(主鍵+指針)
那麼一顆高度爲2的B+樹能存儲的數據爲:117016=18720條,一顆高度爲3的B+樹能存儲的數據爲:11701170*16=21902400(千萬級條)
在這裏插入圖片描述

  1. 爲何採用b+樹,而不用avl樹,b樹,紅黑樹
  • 二叉樹(avl樹,紅黑樹)不管再整樣平衡,它每層都只有兩個節點,當數據量大時,必然會樹的深度很深。磁盤io次數很多,性能很慢
  • B Tree查詢的效率不夠穩定,鍵值其實都是分佈在整棵樹上的節點上的任何一個節點
  • b+樹它很好的利用了磁盤預讀原理將一個節點的大小設爲等於一個頁,這樣每個節點只需要一次I/O就可以完全載入非葉子節點存指針+主鍵,葉子節點存數據:每次查詢的時間複雜度是固定的。分叉(更向更寬廣)就可以更多,樹的高度就可以更小,一次io可以獲取更多的key

索引底層實現

在這裏插入圖片描述

模擬索引的創建和查找過程

在這裏插入圖片描述
a是主鍵,abcd是int型的,e是vachar(20),bcd建立了聯合索引(create index idx_t1_bcd on t1(b asc,c desc,d desc))
show index from t1
此時有兩個索引:PRIMARY【主鍵索引–默認創建的】和idx_t1_bcd
在這裏插入圖片描述
//如果再對b建立普通索引idx_t1_b,那查詢出來就有三個索引了。

局部性原理:
操作系統在執行一行指令的時候,如果這行指令要去取數據,基於局部性原理,操作系統認爲,這一行指令所需要的數據,以及他周圍相鄰的數據,可能是你接下來的立馬要執行的那條指令,也需要的,所以這時候他在執行某條指令的時候,就會取出一頁的數據,這就方便了,你下一條指令可能剛好命中這個條件。【按頁(4kb)加載數據到內存】

innodb中一頁的結構:
在這裏插入圖片描述
t1表爲例:4個int型的,一個vachar型的,則一行需要17Byte,按一頁16kb,則一頁能存964行數據。
假設8條數據用2頁來保存
通過前後指針,兩頁在邏輯上就是連續的了
通過頁目錄和目錄頁來加速查找。(加速了鏈表查詢)
B+樹一個節點可以存儲多個數據
按照主鍵排序
在這裏插入圖片描述
加入一頁只能存兩條數據
聚簇索引
在這裏插入圖片描述
非聚簇索引
在這裏插入圖片描述

聚簇(集)索引的葉子節點就是數據節點,而非聚簇(集)索引的葉子節點仍然是索引節點,只不過有指向對應數據塊的指針。非聚簇(集)索引在innodb引擎中,又叫做二級索引,輔助索引等。
select * fom t1 where b>1查詢優化器判斷出走全表掃描比走索引更快
當select * fom t1 where b>5它就又會走索引了【該情況下走索引成本更低】
7條數據,它要回表7次。不如直接走主鍵索引/全表掃描
全表掃描4頁我就走4次就可以了
在這裏插入圖片描述
不需要回表
在這裏插入圖片描述
需要回表葉子節點仍然是索引節點,它還需要到主鍵索引中查找數據

select b from t1會走索引,因爲索引的葉子節點裏面存的是bcd數據,而b正好的bcd裏面,所以相同數據量,只需要3頁就能存完所有的bcd記錄,但如果全表【主鍵索引】,可能需要6頁才能存完完整的abcde的記錄
111是bcd的值,代表一行數據,淺黃色標出來的是這行數據對應的主鍵,方便對於select * from t1 where b=1,c=1,d=1則可以通過111知道主鍵1,查出該行所有字段的結果了。這樣記錄主鍵就可以,不用記錄所有的數據
知道主鍵1(主鍵1在主鍵索引的葉子節點裏面)此時就要回表【bcd索引叫二級/輔助索引】
在這裏插入圖片描述
bcd是三個int型,一個int佔4字節,又由於bcd都是可以爲null的,這個還需要用1字節去記錄下,所以每個b,c,d就佔5字節,bcd三個就佔15字節

一行的格式
在這裏插入圖片描述
一行最多65535字節(Byte簡寫爲B)
一頁16KB就是16384,行溢出就需要分頁去存儲。

索引失效分析

索引優化口訣
全值匹配我最愛,最左前綴要遵守
帶頭大哥不能死,中間兄弟不能斷
索引列上少計算,範圍之後全完蛋
like百分寫最右, 覆蓋索引不寫 *
不等空值還有or,索引失效要少用
var引號不能丟,SQL高級也不難

索引創建原則口訣:
主鍵索引自動建,頻繁查詢索引現;
查詢關聯其它表,外鍵索引也要看
頻繁更新引不建,where 條件用到算
單鍵/組合選擇難,高併發下組合建
若要速度有體現,排序字段索引建
統計、分組你咋看,索引索引建建鍵;

建立索引a,b,c
where a= 1走索引 1 * *
where b=1不走索引,類似於 * 1 *
字符串匹配一樣1 * * < 644,但是 * 1 *無法和644比較,可能比他大,也可能比他小,這樣計算機在判斷時就只能走全表掃描了
在這裏插入圖片描述
走B索引範圍查詢,查出來的結果集對C而言不一定是有序的。但對b等值查詢(查出來都是一樣的),查出來的對C是有序的,
在這裏插入圖片描述
在這裏插入圖片描述

自動創建索引

ALTER TABLE t1 ADD unique(e);
給e字段添加唯一約束,則建表語句爲UNIQUE KEY e (e),此時會自動給e字段添加唯一索引,對於主鍵,外鍵字段,數據庫也會自動添加索引。

PRIMARY KEY (a), 主鍵a
UNIQUE KEY e (e), 唯一約束e
KEY idx_t1_bcd (b,c,d), 聯合索引bcd
KEY t2_id (f), 外鍵f
KEY t1_b (b) 單值索引b

聚集索引和非聚集索引

  • 聚集索引
    聚集索引表示表中存儲的數據按照索引的順序存儲,檢索效率比非聚集索引高,但對數據更新影響較大;該索引中鍵值的邏輯順序決定了表中相應行的物理順序。聚集索引類似於電話簿,後者按姓氏排列數據。由於聚集索引規定數據在表中的物理存儲順序,因此一個表只能包含一個聚集索引。但該索引可以包含多個列(組合索引),就像電話簿按姓氏和名字進行組織一樣。【外存表現:數據與索引放在同一文件裏;內存表現:b+樹中葉節點就是最終的數據節點

  • 非聚集索引
    數據存儲在一個地方,索引存儲在另一個地方,索引帶有指針指向數據的存儲位置。對於非聚集索引,可以爲在表非聚集索引中查找數據時常用的每個列創建一個非聚集索引。有些書籍包含多個索引。例如,一本介紹園藝的書可能會包含一個植物通俗名稱索引,和一個植物學名索引,因爲這是讀者查找信息的兩種最常用的方法。【外存表現:數據與索引放在不同文件裏;內存表現:b+樹中葉節點仍然是索引節點,但它有一個指向最終數據的指針

  • 在數據庫中通過什麼描述聚集索引與非聚集索引的?
    索引是通過二叉樹的形式進行描述的,我們可以這樣區分聚集與非聚集索引的區別:聚集索引的葉節點就是最終的數據節點,而非聚集索引的葉節仍然是索引節點,但它有一個指向最終數據的指針。
    二者的區別
    講的很全面

事務

參考我的mysql事務專題博客

注意點

  1. mysql裏的utf8-mb4是最全的utf8,支持表情符等
  2. vachar(20)這裏的20指20個字符,而非字節
不同的字符所佔的字節是不同的。
ASCII碼:
一個英文字母(不分大小百寫)佔一個字節的空間,度一箇中文漢字佔兩個字節的空間。一個二進制數字序問列,在計算機中作爲一個數字單元,一般爲8位二進制數,換算爲十進制。最小值0,最答大值255。如一個ASCII碼就是一個字節。
UTF-8編碼:
一個英文字符等於一個字節,一箇中文(專含繁體)等於三屬個字節。
Unicode編碼:
一個英文等於兩個字節,一箇中文(含繁體)等於兩個字節。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章