目錄
- 1、mysql的隔離級別
- 2、MYSQL性能優化
- 常用5種方式
- 3、索引詳解
- 1、何為索引,有什么用?
- 2、索引的優缺點
- 4、什么情況下需要建索引?
- 5、什么情況下不建索引?
- 6、索引的底層資料結構
- 1、hash表
- Hash 沖突 問題
- 既然哈希表這么快, 為什么MySQL 沒有使用其作為索引的資料結構呢?
- 2、B 樹& B+樹
- B 樹& B+樹兩者有何異同呢?
- 1、hash表
- 7、Hash索引和B+樹索引的區別?
- 8、為什么B+樹比B樹更適合實作資料庫索引?
- 9、索引有什么分類?
- 10、什么是最左匹配原則?
- 11、MySQL聚簇和非聚簇索引
- 01、InnoDB中
- 02、MYISAM中
- 03、使用聚簇索引的優勢
- 05、為什么主鍵通常建議使用自增ID
- 12、什么是覆寫索引?
- 13、索引的設計原則?
- 14、什么情況下無法利用索引(索引失效)
- 15、什么是前綴索引?
- 16、常見的存盤引擎有哪些?
- 17、 Mysql鎖有哪些、如何理解
- 18、 Mysql慢查詢如何優化
- 19、 Explain陳述句結果中查詢的各個欄位的意思
- 20、 Innodb如何實作事務的
- 21、 Redis和Mysql如何保證資料一致
- 22、 索引的基本原理
- 23、 MyISAM和innoDb的區別
- 24、ACID靠什么保證的?
- 25、 什么是MVCC
- 26、關心過業務系統里面的sql耗時嗎?統計過慢查詢嗎?對慢查詢都怎么優化?
- 25、mysql中char與varchar的區別
- 26、 mysql中的delete , drop 和truncate 區別
- 27、關于sql和MySQL的陳述句執行順序
- 1、sql執行順序
- 2、mysql的執行順序
- 1、SELECT陳述句定義
- 28、事務的四大特性
- 29、 大表怎么優化?
- 30、bin log/redo log/undo log
- 31、bin log和redo log有什么區別?
- 32、 分庫分表
- 33、 having和where的區別?
- 34、 樂觀鎖和悲觀鎖是什么?
1、mysql的隔離級別
四種隔離級別:
-
READ-UNCOMMITTED(讀取未提交): 最低的隔離級別,允許讀取尚未提交的資料變更, 可能會導致臟讀、幻讀或不可重復讀 ,
-
READ-COMMITTED(讀取已提交): 允許讀取并發事務已經提交的資料, 可以阻止臟讀,但是幻讀或不可重復讀仍有可能發生 ,
-
REPEATABLE-READ(可重復讀): 對同一欄位的多次讀取結果都是一致的,除非資料是被本身事務自己所修改, 可以阻止臟讀和不可重復讀,但幻讀仍有可能發生 ,
-
SERIALIZABLE(可串行化): 最高的隔離級別,完全服從ACID的隔離級別,所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說, 該級別可以防止臟讀、不可重復讀以及幻讀
隔離級別臟讀不可重復讀幻讀READ UNCONMMITTED可能可能可能READ COMMITTED不可能可能可能REPRATABLE READ不可能不可能可能SERIALIZABLE不可能不可能不可能
1、 臟讀:A,B兩事務,A事務會讀取到B事務未提交的資料,然后B因為某些原因回滾資料,所以A就讀取了B沒有提交的資料,也稱臟資料,
2、 不可重復讀:在A事務中對同一資料兩次查詢不一致,可能原因是在A事務提交之前B事務對該資料進行了操作
3、 幻讀:當某個事務在讀取某個范圍內的記錄時,另外一個事務又在該范圍內插入了新的記錄,當之前的事務再次讀取該范圍的記錄時,會產生幻行,就像產生幻覺一樣,這就是發生了幻讀,
-
不可重復讀和臟讀的區別 是,臟讀是某一事務讀取了另一個事務未提交的臟資料,而不可重復讀則是讀取了前一事務提交的資料,
-
幻讀和不可重復讀都是讀取了另一條已經提交的事務,不同的是不可重復讀的重點是修改,幻讀的重點在于新增或者洗掉,
-
事務隔離就是為了解決上面提到的臟讀、不可重復讀、幻讀這幾個問題,
2、MYSQL性能優化
常用5種方式
- 1、最大連接數優化
**修改my.ini檔案(永久修改)**
- 2、啟用查詢快取
特別注意:查詢快取從MySQL 5.7.20開始已被棄用,并在MySQL 8.0中被洗掉,、
-
一種說法是不建議使用查詢快取,因為查詢快取往往弊大于利,查詢快取的失效非常頻繁,只要有對一個表的更新,這個表上的所有的查詢快取都會被清空,因此很可能你費勁地把結果存起來,還沒使用呢,就被一個更新全清空了,對于更新壓力大的資料庫來說,查詢快取的命中率會非常低,除非你的業務有一張靜態表,很長時間更新一次,比如系統配置表,那么這張表的查詢才適合做查詢快取,
-
3、引擎優化
MyISAM存盤引擎:
場景 :如果表主要是用于插入新記錄和讀出記錄,那么選擇MyISAM能實作處理高效率,
優點:MyISAM引擎能提供較高的查詢效率,適用于對資料進行頻繁查詢操作的資料表(InnoDB提供提交、回滾、崩潰恢復能力及并發控制能力,適用于對資料更新操作頻率高的資料表)
- 4、索引優化
這里是便于查詢可以設定索引,讓查詢效率變高.
聚合索引按照從左到右的匹配原則,也就是必須先匹配ID才能匹配name查詢,
全文檢索的查詢方式:
SELECT * FROM article WHERE MATCH(title, content) AGAINST('查詢字串')
全文索引只適合MyISAM引擎的資料表,并且只能對英文進行檢索
- 5、SQL陳述句優化
SQL優化的重心是查詢優化,查詢優化的重心是建立索引,所以查詢優化主要是避免出現導致索引失效的查詢,
①避免在索引列上出現null,
②不要在索引列上進行算術運算,:select age+1 from user
③避免實作!=或者<>、is null或者is not null、in等可能導致全表遍歷的操作,
④模糊查詢只能使用右邊%,
⑤where陳述句后盡可能少用小括號、或者不要出現小括號嵌套小括號,
3、索引詳解
1、何為索引,有什么用?
索引是存盤引擎用于提高資料庫表的訪問速度的一種 資料結構 ,,常見的索引結構有:Hash、B數,B+樹,
索引的作用就是相當于目錄的作用,打個比方: 我們在查字典的時候,如果沒有目錄,那我們就只能一頁一頁的去找我們需要查的 那個字,速度很慢,如果有目錄了,我們只需要先去目錄里查找字的位置,然后直接翻到那一頁就行了,
資料是存盤在磁盤上的,查詢資料時,如果沒有索引,會加載所有的資料到記憶體,依次進行檢索,讀取磁盤次數較多,有了索引,就不需要加載所有資料,因為B+樹的高度一般在2-4層,最多只需要讀取2-4次磁盤,查詢速度大大提升,
2、索引的優缺點
-
優點:
-
加快資料查找的速度
-
為用來排序或者是分組的欄位添加索引,可以 加快分組和排序的速度
-
加快表與表之間連接的速度
-
-
缺點:
-
建立索引需要 占用物理空間
-
會降低表的增刪改的效率,因為每次對表記錄進行增刪改,需要進行 動態維護索引 ,導致增刪改時間變長
-
注意: 使用索引一定能提高查詢性能嗎?
大多數情況下,索引查詢都是比全表掃描要快的,但是如果資料庫的資料量不大,那么使用索引也不一定能夠帶來很大提升,
4、什么情況下需要建索引?
- 經常用于查詢的欄位
- 經常用于連接的欄位建立索引,可以加快連接的速度
- 經常需要排序的欄位建立索引,因為索引已經排好序,可以加快排序查詢速度
5、什么情況下不建索引?
where條件中用不到的欄位不適合建立索引- 表記錄較少
- 需要經常增刪改
- 參與列計算 的列不適合建索引
- 區分度不高 的欄位不適合建立索引,如性別等
6、索引的底層資料結構
1、hash表
哈希索引是基于哈希表實作的,對于每一行資料,存盤引擎會對索引列進行哈希計算得到哈希碼,并且哈希演算法要盡量保證不同的列值計算出的哈希碼值是不同的,將哈希碼的值作為哈希表的key值,將指向資料行的指標作為哈希表的value值,這樣查找一個資料的時間復雜度就是O(1),一般多用于精確查找,
是鍵值對的集合,通過鍵(key)即可快速取出對應的值(value),因此哈希表可以快速檢索資料(接近 O(1)
-
Hash 沖突 問題
? 也就是說多個不同的 key 最后得到的 index 相同,通常情況下,我們常用的解決辦法是 鏈地址法 ,鏈地址法就是將哈希沖突資料存放在鏈表中,就比如 JDK1.8 之前
HashMap就是通過鏈地址法來解決哈希沖突的,不過,JDK1.8 以后HashMap為了減少鏈表過長的時候搜索時間過長引入了紅黑樹,
-
既然哈希表這么快, 為什么MySQL 沒有使用其作為索引的資料結構呢?
1.Hash 沖突問題 :我們上面也提到過Hash 沖突了,不過對于資料庫來說這還不算最大的缺點,
2.Hash 索引不支持順序和范圍查詢(Hash 索引不支持順序和范圍查詢是它最大的缺點: 假如我們要對表中的資料進行排序或者進行范圍查詢,那 Hash 索引可就不行了,
2、B 樹& B+樹
B 樹,全稱為 多路平衡查找樹 ,B+ 樹是 B 樹的一種變體,B 樹和 B+樹中的 B 是
Balanced (平衡)的意思,
目前大部分資料庫系統及檔案系統都采用 B-Tree 或其變種 B+Tree 作為索引結構,
進行查找操作時,首先在根節點進行二分查找,找到
key所在的指標,然后遞回地在指標所指向的節點進行查找,直到查找到葉子節點,然后在葉子節點上進行二分查找,找出
key所對應的資料項,
-
B 樹& B+樹兩者有何異同呢?
- B 樹的所有節點既存放鍵(key) 也存放 資料(data),而 B+樹只有葉子節點存放 key 和 data,其他內節點只存放 key,
- B 樹的葉子節點都是獨立的;B+樹的葉子節點有一條參考鏈指向與它相鄰的葉子節點,
- B 樹的檢索的程序相當于對范圍內的每個節點的關鍵字做二分查找,可能還沒有到達葉子節點,檢索就結束了,而 B+樹的檢索效率就很穩定了,任何查找都是從根節點到葉子節點的程序,葉子節點的順序檢索很明顯,
- innoDB存盤引擎中的頁大小為16kb,一般主鍵型別int(占4位元組)或者bigint(占8位元組),指標型別也一般占4或8位元組,也就是說一個頁(B+Tree中的一個節點)中大概可以存盤16KB/(8B+8B)=1K個鍵值,也就是說一個深度為3的B+Tree索引跨行業維護10^3 10^3 10^3=10億條記錄(8億)
- 實際情況中,每個節點并不能【填充滿,因此在資料庫中,B+Tree的高度一般都在2-4層,mysql的innoDB索引引擎在設計的時候是將根節點常駐放在記憶體中的,也就是說查找某一鍵值記錄最多只需要1-3次I/O操作,注意頂層頁常駐記憶體
7、Hash索引和B+樹索引的區別?
-
哈希索引 不支持排序 ,因為哈希表是無序的,
-
哈希索引 不支持范圍查找 ,
-
哈希索引 不支持模糊查詢 及多列索引的最左前綴匹配,
-
因為哈希表中會 存在哈希沖突 ,所以哈希索引的性能是不穩定的,而B+樹索引的性能是相對穩定的,每次查詢都是從根節點到葉子節點,
8、為什么B+樹比B樹更適合實作資料庫索引?
-
由于B+樹的資料都存盤在葉子結點中,葉子結點均為索引,方便掃庫,只需要掃一遍葉子結點即可,但是B樹因為其分支結點同樣存盤著資料,我們要找到具體的資料,需要進行一次中序遍歷按序來掃,所以B+樹更加適合在區間查詢的情況,而在資料庫中基于范圍的查詢是非常頻繁的,所以通常B+樹用于資料庫索引,
-
B+樹的節點只存盤索引key值,具體資訊的地址存在于葉子節點的地址中,這就使以頁為單位的索引中可以存放更多的節點,減少更多的I/O支出,
-
B+樹的查詢效率更加穩定,任何關鍵字的查找必須走一條從根結點到葉子結點的路,所有關鍵字查詢的路徑長度相同,導致每一個資料的查詢效率相當,
9、索引有什么分類?
1、 主鍵索引 :名為primary的唯一非空索引,不允許有空值,
2、 唯一索引 :索引列中的值必須是唯一的,但是允許為空值,唯一索引和主鍵索引的區別是:唯一約束的列可以為null且可以存在多個null值,唯一索引的用途:唯一標識資料庫表中的每條記錄,主要是用來防止資料重復插入,創建唯一索引的SQL陳述句如下:
ALTER TABLE table_name
ADD CONSTRAINT constraint_name UNIQUE KEY(column_1,column_2,...);
3、 組合索引 :在表中的多個欄位組合上創建的索引,只有在查詢條件中使用了這些欄位的左邊欄位時,索引才會被使用,使用組合索引時需遵循最左前綴原則,
4、 普通索引( 單值索引)
5、 全文索引 :只有在MyISAM引擎上才能使用,只能在CHAR、VARCHAR和TEXT型別欄位上使用全文索引,
10、什么是最左匹配原則?
如果 SQL 陳述句中用到了組合索引中的最左邊的索引,那么這條 SQL 陳述句就可以利用這個組合索引去進行匹配,當遇到范圍查詢(
>、<、between、like)就會停止匹配,后面的欄位不會用到索引,
(a,b,c)建立索引,查詢條件使用 a/ab/abc 會走索引,使用 bc 不會走索引,如果查詢條件為
a = 1 and b > 2 and c = 3,那么a、b個字兩段能用到索引,而c無法使用索引,因為b欄位是范圍查詢,導致后面的欄位無法使用索引,如下圖,對(a, b) 建立索引,a 在索引樹中是全域有序的,而 b 是全域無序,區域有序(當a相等時,會根據b進行排序),
11、MySQL聚簇和非聚簇索引
都是B+樹的資料結構
-
1 、聚簇索引: 葉子節點將資料存盤和索引存放在一起,并且是按照一定順序組織的,找到索引也就是找到資料,資料的物理存放順序和索引順序是一致的,即:只要索引相鄰,那么對應的資料一定也是相鄰的存放在磁盤上的
-
2 、非聚簇索引: 將資料存盤和索引分開存盤的,索引結構的葉子節點指向資料對應的位置
葉子節點不存盤資料、存盤的是資料的行地址(索引),也就是說根據索引查詢到的資料行的位置,再取磁盤查找資料,這個就類似一本樹的目錄,
在innoDB中,在聚簇索引之上創建的索引是非聚簇索引,非聚簇索引是輔佐索引,像復合索引、前綴索引、唯一索引,輔佐索引的葉子節點存盤的不再是行的物理位置,而是主鍵值,輔佐索引訪問資料總是需要二次查找
01、InnoDB中
-
InnoDB使用的是聚簇索引,將主鍵組織到一個棵樹中,而行資料就存盤在葉子節點上,若使用“where id = 4”這樣的條件查找主鍵,則按照B+樹的檢索演算法,即可查找到對應的葉子節點,之后獲得行資料
-
若對name列進行條件搜索,則需要兩步:
- 第一步:在輔佐索引B+樹中檢索name,到達其葉子節點獲取對應的主鍵
-
第二部:使用主鍵在主鍵索引B+樹再執行一次B+樹檢索操作,最終達到葉子節點可獲取整行資料(重點:在于通過其他鍵需要建立輔佐索引)
-
聚簇索引默認是主鍵,如果表中沒有定義主鍵InnoDB會選擇一個唯一且非空的索引代替,如果沒有這樣的索引,innoDB會隱式的定義一個主鍵(類似Oracle的Rowid)來作為聚簇索引,如果已經射設定了主鍵為聚簇索引,想希望單獨設定聚簇索引,必須先洗掉主鍵,然后添加我們想要的聚簇索引,最終在恢復主鍵設定即可
02、MYISAM中
MYISAM使用的是非聚簇,非聚簇索引的兩棵B+樹看上去沒有太大的區別,節點的結構完全一致,至少2存盤的內瑞內容不一樣,主鍵索引B+樹的節點的存盤了主鍵,輔佐索引B+樹存盤了輔佐鍵,表的資料在獨立的地方,這兩課B+樹的葉子節點都使用地址指向真正的表資料,對表資料來說,這兩個鍵沒有任何差別,由于索引樹是獨立的,通過輔佐鍵檢索無需訪問主鍵的索引樹
03、使用聚簇索引的優勢
- 問題:每次使用輔佐索引檢索都需要經過兩次的B+樹查找,看上去聚簇索引的效率明顯低于非聚簇索引,這不是多次一舉嗎,聚簇索引的優勢在哪呢?
1、 由于行資料和聚簇索引的葉子節點存盤在一起,在同一頁會有多條行資料,訪問同一資料頁不同行記錄時,已經把頁的加載到Buffer(緩沖器),再次訪問的時,會再記憶體中完成訪問,不必再訪問磁盤,這樣主鍵和行資料是一起載入記憶體的,找到葉子節點就立刻將行資料回傳了,如果按照ID來組織資料,獲取資料更快
2、 輔佐索引的葉子節點,存盤主鍵值,而不是資料的存放地址,好處是當行資料發生變化時,索引樹的節點也需要分裂變化;或者是我們需要查找的資料,在上一次IO讀寫的快取中沒有,需要發送一次新的IO操作時,可以避免對輔佐索引的維護作業,只需要維護聚簇索引樹就好,另外好處就是,因為輔佐索引存放的時主鍵值,減少輔佐索引占用的存盤空間大小
05、為什么主鍵通常建議使用自增ID
12、什么是覆寫索引?
select的資料列只用從索引中就能夠取得,不需要 回表 進行二次查詢,也就是說查詢列要被所使用的索引覆寫,對于
innodb表的二級索引,如果索引能覆寫到查詢的列,那么就可以避免對主鍵索引的二次查詢,
不是所有型別的索引都可以成為覆寫索引,覆寫索引要存盤索引列的值,而哈希索引、全文索引不存盤索引列的值,所以MySQL使用b+樹索引做覆寫索引,
13、索引的設計原則?
-
索引列的 區分度越高 ,索引的效果越好,比如使用性別這種區分度很低的列作為索引,效果就會很差,
-
盡量使用 短索引 ,對于較長的字串進行索引時應該指定一個較短的前綴長度,因為較小的索引涉及到的磁盤I/O較少,查詢速度更快,
-
索引不是越多越好,每個索引都需要額外的物理空間,維護也需要花費時間,
-
利用 最左前綴原則 ,
14、什么情況下無法利用索引(索引失效)
導致索引失效的情況:
-
1、對于組合索引,不是使用組合索引最左邊的欄位,則不會使用索引
-
2、查詢陳述句中使用like關鍵字
以%開頭的like查詢如
%abc,無法使用索引;非%開頭的like查詢如abc%,相當于范圍查詢,會使用索引
-
3、查詢陳述句中使用OR關鍵字
查詢條件使用
or連接
-
如果前后條件的列都是索引那么可以利用索引
-
如果前后索引中華有一列不是索引,則無法利用索引
-
4、查詢條件中列型別是字串,沒有使用引號,可能會因為型別不同發生隱式轉換,使索引失效
-
5、對索引列進行運算
15、什么是前綴索引?
有時需要在很長的字符列上創建索引,這會造成索引特別大且慢,使用前綴索引可以避免這個問題,
前綴索引是指對文本或者字串的前幾個字符建立索引,這樣索引的長度更短,查詢速度更快,
創建前綴索引的關鍵在于選擇足夠長的前綴以 保證較高的索引選擇性 ,索引選擇性越高查詢效率就越高,因為選擇性高的索引可以讓MySQL在查找時過濾掉更多的資料行,
16、常見的存盤引擎有哪些?
MySQL中常用的四種存盤引擎分別是: MyISAM 、 InnoDB 、 MEMORY 、 ARCHIVE ,MySQL 5.5版本后默認的存盤引擎為InnoDB,
17、 Mysql鎖有哪些、如何理解
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-uVWXa7Hj-1650358046863)(https://pizximfzuc.feishu.cn/space/api/box/stream/download/asynccode/?code=MjZhZDY3OTBhMzE1ODE4MGUxZTUyZTEyMjFhZjU0OTJfQVpRSDlaaERqU05HWVNrWlRwWjNzUDNobThvVzN1cUtfVG9rZW46Ym94Y25sVEtmcDFkdXYzZjVjbkJPbGkwUDRlXzE2NTAzNTc2NTY6MTY1MDM2MTI1Nl9WNA)]
18、 Mysql慢查詢如何優化
19、 Explain陳述句結果中查詢的各個欄位的意思
20、 Innodb如何實作事務的
Innodb通過Buffer Pool,Redo Log,Undo Log來實作事務,以一個update陳述句為例:
-
innodb在收到一個update陳述句后,會根據條件找到資料所在葉,并將該頁快取在buffer Pool中
-
執行update陳述句,修改Buffer Pool中的資料,也就是記憶體中的資料
-
針對update陳述句生成一個RedoLog物件,兵存入LogBuffer中
-
針對update陳述句生成的undoLog日志,用于事務回滾
-
如果事務提交,則把RedoLog日物件進行持久化,后續還有其他機制將Buffer Pool中修改的資料頁持久化到磁盤中
-
如果事務回滾,則利用undoLog日志進行回滾
21、 Redis和Mysql如何保證資料一致
1、先更新Mysql,再更新Redis,如果redis失敗,依舊可能資料不一致
2、先洗掉redis中資料,再更新mysql,再次查詢的時候再更新資料添加到快取中,(這個方案解決了1的問題),但是再高并發的情況下效率比較低下,并且還是可能有資料不一致的可能,比如執行緒1洗掉后,再更新msql時,但是此時有一個執行緒2進來查詢時,就會將mysql中老資料又查詢到redis中,
3、``延遲雙刪,步驟:先洗掉redis中的資料,再更新mysql,再隔幾百毫秒再洗掉redis中快取資料,這樣就算在更新mysql時,有其他執行緒讀取mysql時,把老資料讀到redis中也會很快被刪掉
22、 索引的基本原理
索引是用來快速查詢有特定值的記錄,如果沒有索引,一般來說執行查詢時候需要查詢全表
索引基本原理: 把無序的資料變成有序的查詢
-
1、把創建索引的列的內容進行排序
-
2、對排序結果進行倒排列
-
3、在倒排表后面內容上拼接上資料地址鏈
-
4、在查詢的時候,先拿到倒排表內容,再取出資料地址鏈,從而就取出具體資料
23、 MyISAM和innoDb的區別
MyISAM:
-
不支持事務,但是每一次的查詢都是原子的
-
支持表級鎖,即每次操作都會對表進行加鎖
-
存盤表的總行數
-
一個MyISAM表有三個檔案:索引檔案、表結構檔案、資料檔案
-
采用非聚簇索引,索引檔案的資料有存盤指向資料檔案的指標,輔助索引與主索引基本一致,但是輔助索引不用保證唯一性
InnoDb:
-
支持ACID的事務,支持事務的四種隔離級別
-
支持行級鎖與外鍵約束:因此可以支持寫并發
-
不存盤總行數
-
一個InnoDb引擎存盤在一個檔案空間(共享表空間,表大小不受作業系統的控制,一個表可能分布在多個文化里),也可能為多個(設定為獨立表空,表大小受作業系統檔案大小的 控制,一般為2G),受作業系統檔案大小的限制
-
主鍵索引采用聚簇索引(索引的資料域存盤資料檔案本身),輔助索引的資料域存盤主鍵的值;因此從輔助索引查找資料,需要先通過輔佐索引找到主鍵值,再訪問主索引;最好使用自增主鍵,防止插入資料時,為維護B+樹結構,檔案的大整
24、ACID靠什么保證的?
-
A原子性由undo log日志保證,他記錄了需要回滾的日志資訊,事務回滾時撤銷已近執行成功的sql
-
C 一致性由其他三大特性保證、資料上的一致需要程式代碼要保證業務上的一致性
-
I 隔離性 由MVCC來保證的
-
D 持久性 由記憶體和redo log來保證,mysql修改資料同時在記憶體和redo log記錄這次操作,嘎機的時候可以從redo log恢復
redo log的刷盤會在系統空閑時候進行
25、 什么是MVCC
多版本并發控制:讀取資料時通過一種類似快照的方式將資料保存下來,這樣讀鎖和寫鎖就不沖突了,不同的事務session會看到自己的特定版本的資料,版本鏈
MVCC只在READ COOMMITED 和REPETABLE READ 兩個隔離級別下作業,其他兩個隔離級別和MVCC沖突不兼容,因為READ UNCOMMITED 總是讀取最新的資料行,而不是 符合當前事務版本的資料行,而SESRIALIZABLE則會對所有的讀取行加鎖
聚簇索引記錄中有兩個必要的隱藏列
trx_id:用來存盤每次對某條聚簇索引記錄進行修改的時候事務id
roll_pointer:每次對哪條索引記錄進行修改的時候,都會把老版本寫入undo日志中,這個roll_pointer就是保存了一個指標,它指向這條聚簇索引記錄的上一個版本的位置,通過它來獲取上一個版本的記錄資訊,(注意插入操作的undo日志沒有這個屬性,因為它沒有老版本)
使用事務更新行記錄的時候,就會生成版本鏈,執行程序如下:
- 用排他鎖鎖住該行;
- 將該行原本的值拷貝到
undo log,作為舊版本用于回滾;
- 修改當前行的值,生成一個新版本,更新事務id,使回滾指標指向舊版本的記錄,這樣就形成一條版本鏈,
已提交讀和可重復讀的區別在于他們生成的ReadView的策瑜不同
無法復制加載中的內容
接下來了解下read view的概念,
read view可以理解成將資料在每個時刻的狀態拍成“照片”記錄下來,在獲取某時刻t的資料時,到t時間點拍的“照片”上取資料,
在read view內部維護一個活躍事務鏈表,表示生成read view的時候還在活躍的事務,這個鏈表包含在創建read view之前還未提交的事務,不包含創建read view之后提交的事務,
不同隔離級別創建read view的時機不同,
-
read committed:每次執行select都會創建新的read_view,保證能讀取到其他事務已經提交的修改,
-
repeatable read:在一個事務范圍內,第一次select時更新這個read_view,以后不會再更新,后續所有的select都是復用之前的read_view,這樣可以保證事務范圍內每次讀取的內容都一樣,即可重復讀,
總結 :InnoDB 的MVCC是通過 read view 和版本鏈實作的,版本鏈保存有歷史版本記錄,通過read view 判斷當前版本的資料是否可見,如果不可見,再從版本鏈中找到上一個版本,繼續進行判斷,直到找到一個可見的版本,
26、關心過業務系統里面的sql耗時嗎?統計過慢查詢嗎?對慢查詢都怎么優化?
在業務系統中,除了使用主鍵進行查詢,還有其他的在測驗庫上測驗其耗時,慢查詢的統計一般主要由運維在做,會定期的將業務中的慢查詢反饋給我們、慢查詢的優化首先需要慢的原因是什么?是查詢條件沒有命中索引?是load了需要的資料列,還是資料量過大?
所以優化也是針對這三個方向來的,
-
首先分析陳述句,看看是不是load了額外不需要的資料,可能是查詢了多余的行并且拋棄掉了,可能是加載了許多結果中 炳不需要的列,對陳述句進行分析以及重寫
-
分析陳述句的執行計劃,獲得其使用索引的情況,之后修改陳述句或者索引,使得陳述句可以盡可能的命中索引
-
如果陳述句的優化已經無法進行,可以考慮表中的資料量是否過大,如果是的話可以進行考慮分表
25、mysql中char與varchar的區別
都是用來存盤字串的,只是他們的保存方式不一樣罷了
- char有固定的長度,而varchar屬于可變長的字符型別,char 長度是固定的,不管你存盤的資料是多少他都會都固定的長度,而varchar則處可變長度但他要在總長度上加1字符,這個用來存盤位置
26、 mysql中的delete , drop 和truncate 區別
-
1、delete和truncate僅僅洗掉表資料,trop連表資料和結構一起洗掉,打個比方delete 是單殺,truncate 是團滅,drop 是把電腦摔了,
-
2、delete 是 DML 陳述句,操作完以后如果沒有不想提交事務還可以回滾,truncate 和 drop 是 DDL 陳述句,操作完馬上生效,不能回滾,打個比方,delete 是發微信說分手,后悔還可以撤回,truncate 和 drop 是直接扇耳光說滾,不能反悔,
-
3、執行的速度上, drop>truncate>delete ,打個比方,drop 是神舟火箭,truncate 是和諧號動車,delete 是自行車,
delete 是洗掉一條資料,truncate是將這個表的所有資料都洗掉,這兩種不洗掉表的結構,可以用
27、關于sql和MySQL的陳述句執行順序
1、sql執行順序
-
from
-
join
-
on
-
where
-
group by(開始使用select中的別名,后面的陳述句中都可以使用)
-
avg,sum....
-
having
-
select
-
distinct
-
order by
-
limit
從這個順序中我們不難發現,所有的 查詢陳述句都是從from開始執行的,在執行程序中,每個步驟都會為下一個步驟生成一個虛擬表,這個虛擬表將作為下一個執行步驟的輸入,
第一步:首先對from子句中的前兩個表執行一個笛卡爾乘積,此時生成虛擬表 vt1(選擇相對小的表做基礎表),
第二步:接下來便是應用on篩選器,on 中的邏輯運算式將應用到 vt1 中的各個行,篩選出滿足on邏輯運算式的行,生成虛擬表 vt2 ,
第三步:如果是outer join 那么這一步就將添加外部行,left outer jion 就把左表在第二步中過濾的添加進來,如果是right outer join 那么就將右表在第二步中過濾掉的行添加進來,這樣生成虛擬表 vt3 ,
第四步:如果 from 子句中的表數目多余兩個表,那么就將vt3和第三個表連接從而計算笛卡爾乘積,生成虛擬表,該程序就是一個重復1-3的步驟,最終得到一個新的虛擬表 vt3,
第五步:應用where篩選器,對上一步生產的虛擬表參考where篩選器,生成虛擬表vt4,在這有個比較重要的細節不得不說一下,對于包含outer join子句的查詢,就有一個讓人感到困惑的問題,到底在on篩選器還是用where篩選器指定邏輯運算式呢?on和where的最大區別在于,如果在on應用邏輯表達式那么在第三步outer join中還可以把移除的行再次添加回來,而where的移除的最終的,舉個簡單的例子,有一個學生表(班級,姓名)和一個成績表(姓名,成績),我現在需要回傳一個x班級的全體同學的成績,但是這個班級有幾個學生缺考,也就是說在成績表中沒有記錄,為了得到我們預期的結果我們就需要在on子句指定學生和成績表的關系(學生.姓名=成績.姓名)那么我們是否發現在執行第二步的時候,對于沒有參加考試的學生記錄就不會出現在vt2中,因為他們被on的邏輯運算式過濾掉了,但是我們用left outer join就可以把左表(學生)中沒有參加考試的學生找回來,因為我們想回傳的是x班級的所有學生,如果在on中應用學生.班級='x'的話,left outer join會把x班級的所有學生記錄找回(感謝網友康欽謀__康欽苗的指正),所以只能在where篩選器中應用學生.班級='x' 因為它的過濾是最終的,
第六步:group by 子句將中的唯一的值組合成為一組,得到虛擬表vt5,如果應用了group by,那么后面的所有步驟都只能得到的vt5的列或者是聚合函式(count、sum、avg等),原因在于最終的結果集中只為每個組包含一行,這一點請牢記,
第七步:應用cube或者rollup選項,為vt5生成超組,生成vt6.
第八步:應用having篩選器,生成vt7,having篩選器是第一個也是為唯一一個應用到已分組資料的篩選器,
第九步:處理select子句,將vt7中的在select中出現的列篩選出來,生成vt8.
第十步:應用distinct子句,vt8中移除相同的行,生成vt9,事實上如果應用了group by子句那么distinct是多余的,原因同樣在于,分組的時候是將列中唯一的值分成一組,同時只為每一組回傳一行記錄,那么所以的記錄都將是不相同的,
第十一步:應用order by子句,按照order_by_condition排序vt9,此時回傳的一個游標,而不是虛擬表,sql是基于集合的理論的,集合不會預先對他的行排序,它只是成員的邏輯集合,成員的順序是無關緊要的,對表進行排序的查詢可以回傳一個物件,這個物件包含特定的物理順序的邏輯組織,這個物件就叫游標,正因為回傳值是游標,那么使用order by 子句查詢不能應用于表運算式,排序是很需要成本的,除非你必須要排序,否則最好不要指定order by,最后,在這一步中是第一個也是唯一一個可以使用select串列中別名的步驟,
第十二步:應用top選項,此時才回傳結果給請求者即用戶,
2、mysql的執行順序
1、SELECT陳述句定義
一個完成的SELECT陳述句包含可選的幾個子句,SELECT陳述句的定義如下:
SQL代碼
<SELECT clause> [<FROM clause>] [<WHERE clause>] [<GROUP BY clause>] [<HAVING clause>] [<ORDER BY clause>] [<LIMIT clause>]
2、SELECT陳述句執行順序
SELECT陳述句中子句的執行順序與SELECT陳述句中子句的輸入順序是不一樣的,所以并不是從SELECT子句開始執行的,而是按照下面的順序執行:
開始->FROM子句->WHERE子句->GROUP BY子句->HAVING子句->ORDER BY子句->SELECT子句->LIMIT子句->最終結果
28、事務的四大特性
事務特性ACID : 原子性 (Atomicity)、 一致性 (Consistency)、 隔離性 (Isolation)、 持久性 (Durability),
-
原子性 是指事務包含的所有操作要么全部成功,要么全部失敗回滾,
-
一致性 是指一個事務執行之前和執行之后都必須處于一致性狀態,比如a與b賬戶共有1000塊,兩人之間轉賬之后無論成功還是失敗,它們的賬戶總和還是1000,
-
隔離性 ,跟隔離級別相關,如
read committed,一個事務只能讀到已經提交的修改, -
持久性 是指一個事務一旦被提交了,那么對資料庫中的資料的改變就是永久性的,即便是在資料庫系統遇到故障的情況下也不會丟失提交事務的操作,
29、 大表怎么優化?
某個表有近千萬資料,查詢比較慢,如何優化?
當MySQL單表記錄數過大時,資料庫的性能會明顯下降,一些常見的優化措施如下:
-
限定資料的范圍,比如:用戶在查詢歷史資訊的時候,可以控制在一個月的時間范圍內;
-
讀寫分離:經典的資料庫拆分方案,主庫負責寫,從庫負責讀;
-
通過分庫分表的方式進行優化,主要有垂直拆分和水平拆分,
30、bin log/redo log/undo log
mysql日志主要有查詢日志、慢查詢日志、事務日志、錯誤日志、二進制日志,其中比較中亞的是bin log(二進制日志)、redo log(重做日志)、undo log(回滾日志)
- bin log
bin log是MySQL資料庫級別的檔案 ,記錄對MySQL資料庫執行修改的所有操作,不會記錄select等陳述句,主要用于恢復資料庫和同步資料庫
- redo log
redo log是innodb引擎級別,用來記錄innodb存盤引擎的事務日志,不管事務是否提交都會記錄下來,用于資料恢復,當資料庫發生故障,innodb存盤引擎會使用redo log恢復到發生故障前時刻,以此來保證資料的完整性,將引數innodb_flush_log_at_tx_commit設定為1,那么在執行commit時會將redo log同步寫到磁盤,
- undo log
除了記錄
redo log外,當進行資料修改時還會記錄undo log,undo log用于資料的撤回操作,他保留了記錄修改前的內容,通過undo log可實作是事務的回滾,并且可以根據undo log回溯到某個特定的版本資料,實作 MVCC
31、bin log和redo log有什么區別?
-
bin log會記錄所有日志記錄,包括InnoDB、MyISAM等存盤引擎的日志;redo log只記錄innoDB自身的事務日志, -
bin log只在事務提交前寫入到磁盤,一個事務只寫一次;而在事務進行程序,會有redo log不斷寫入磁盤, -
bin log是邏輯日志,記錄的是SQL陳述句的原始邏輯;redo log是物理日志,記錄的是在某個資料頁上做了什么修改,
32、 分庫分表
當單表的資料量達到1000W或100G以后,優化索引、添加從庫等可能對資料庫性能提升效果不明顯,此時就要考慮對其進行切分了,切分的目的就在于減少資料庫的負擔,縮短查詢的時間,
資料切分可以分為兩種方式:垂直劃分和水平劃分,
- 垂直劃分
垂直劃分資料庫是根據業務進行劃分,例如購物場景,可以將庫中涉及商品、訂單、用戶的表分別劃分出成一個庫,通過降低單庫的大小來提高性能,同樣的,分表的情況就是將一個大表根據業務功能拆分成一個個子表,例如商品基本資訊和商品描述,商品基本資訊一般會展示在商品串列,商品描述在商品詳情頁,可以將商品基本資訊和商品描述拆分成兩張表,
優點 :行記錄變小,資料頁可以存放更多記錄,在查詢時減少I/O次數,
缺點 :
優點 :行記錄變小,資料頁可以存放更多記錄,在查詢時減少I/O次數,
缺點 :
-
主鍵出現冗余,需要管理冗余列;
-
會引起表連接JOIN操作,可以通過在業務服務器上進行join來減少資料庫壓力;
-
依然存在單表資料量過大的問題,
-
水平劃分
水平劃分是根據一定規則,例如時間或id序列值等進行資料的拆分,比如根據年份來拆分不同的資料庫,每個資料庫結構一致,但是資料得以拆分,從而提升性能,
優點 :單庫(表)的資料量得以減少,提高性能;切分出的表結構相同,程式改動較少,
缺點 :
-
分片事務一致性難以解決
-
跨節點
join性能差,邏輯復雜 -
資料分片在擴容時需要遷移
33、 having和where的區別?
-
二者作用的物件不同,
where子句作用于表和視圖,having作用于組, -
where在資料分組前進行過濾,having在資料分組后進行過濾,
34、 樂觀鎖和悲觀鎖是什么?
資料庫中的并發控制是確保在多個事務同時存取資料庫中同一資料時不破壞事務的隔離性和統一性以及資料庫的統一性,樂觀鎖和悲觀鎖是并發控制主要采用的技術手段,
-
悲觀鎖:假定會發生并發沖突,在查詢完資料的時候就把事務鎖起來,直到提交事務,實作方式:使用資料庫中的鎖機制,
-
樂觀鎖:假設不會發生并發沖突,只在提交操作時檢查是否資料是否被修改過,給表增加
version欄位,在修改提交之前檢查version與原來取到的version值是否相等,若相等,表示資料沒有被修改,可以更新,否則,資料為臟資料,不能更新,實作方式:樂觀鎖一般使用版本號機制或CAS演算法實作,
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/458684.html
標籤:MySQL
