MySQL
資料庫三大正規化
第一正規化(1NF):要求資料庫表的每一列都是不可分割的原子資料項
第二正規化需要確保資料庫表中的每一列都和主鍵相關,而不能只與主鍵的某一部分相關(主要針對聯合主鍵
第三正規化需要確保資料表中的每一列資料都和主鍵直接相關,而不能間接相關。
連表查詢
內連線返回兩個表中有匹配關係的行
左外連線返回左表中的所有行,即使在右表中沒有匹配的行。未匹配的右表列會包含NULL。
右外同上
全外連線返回兩個表中所有行,包括非匹配行
MySQL如何避免重複插入資料
使用UNIQUE約束
使用INSERT ... ON DUPLICATE KEY UPDATE
如果沒有定義外來鍵約束,那麼就有可能出現學生選了不存在的課程或者刪除了一個課程而忘記從學生表中刪除選修該課程的學生的情況
in和exist
在很多情況下,EXISTS 的效能優於 IN
IN 能夠正確處理子查詢中包含NULL值的情況,而EXISTS 不受子查詢結果中NULL值的影響,因為它關注的是行的存在性,而不是具體值
MySQL的基本函式
concat,length,substring,replace,abs,power,now,curdate,count,sum,max,min,avg
SQL查詢語句的執行順序
查詢語句都是從FROM開始執行,在執行過程中,每個步驟都會生成一個虛擬表,這個虛擬表將作為下一個執行步驟的輸入,最後一個步驟產生的虛擬表即為輸出結果
SQL請求的過程
建立連線,查詢快取,解析 SQL,執行 SQL(預處理,最佳化,執行)
mysql的引擎
InnoDB
MyISAM
MySQL為什麼InnoDB是預設引擎
支援事務,併發效能,崩潰恢復
innodb有行鎖,myisam只有表鎖,redolog崩潰恢復
mysql的innodb與MyISAM的區別
事務,索引結構(是否聚簇),鎖粒度
資料檔案大體分成哪幾種資料檔案
如果有主鍵,預設會使用主鍵作為聚簇索引的索引鍵(key);
如果沒有主鍵,就選擇第一個不包含 NULL 值的唯一列作為聚簇索引的索引鍵(key);
在上面兩個都沒有的情況下,InnoDB 將自動生成一個隱式自增 id 列作為聚簇索引的索引鍵(key)
主鍵索引的 B+Tree 的葉子節點存放的是實際資料,二級索引的 B+Tree 的葉子節點存放的是主鍵值
欄位特性分類
主鍵索引,唯一索引,普通索引,字首索引
什麼欄位適合當做主鍵
唯一性,遞增的趨勢,不建議用業務資料作為主鍵
區別不大的欄位不適合當索引,查出大量資料回表更慢
主鍵用自增ID還是UUID
自增 id,uuid 相對順序的自增 id 來說是毫無規律可言的,新行的值不一定要比之前的主鍵的值要大,所以 innodb 無法做到總是把新行插入到索引的最後,而是需要為新行尋找新的合適的位置從而來分配新的空間
什麼自增ID更快一些,UUID不快嗎,它在B+樹裡面儲存是有序的嗎
主鍵頁就會近乎於順序的記錄填滿,提升了頁面的最大填充率
不會為計算新行的位置而做出額外的消耗
減少了頁分裂和碎片的產生
Mysql中的索引是怎麼實現的
B+樹作為了索引的資料結構,非葉子節點只存放索引
B+樹的特性
所有葉子節點都在同一層,非葉子節點儲存鍵值,葉子節點儲存資料記錄,自平衡
B+樹和B樹的區別
在B+樹中,資料都儲存在葉子節點上,而非葉子節點只儲存索引資訊;而B樹的非葉子節點既儲存索引資訊也儲存部分資料。資料量相同的情況下,B+樹的非葉子節點可以存放更多的索引,因此 B+ 樹可以比 B 樹更「矮胖」,查詢底層節點的磁碟 I/O次數會更少
B+樹的葉子節點使用連結串列相連,便於範圍查詢和順序訪問;B樹的葉子節點沒有連結串列連線。
B+樹的查詢效能更穩定,每次查詢都需要查詢到葉子節點;而B樹的查詢可能會在非葉子節點找到資料,效能相對不穩定
B+樹的葉子節點連結串列是單向還是雙向
雙向的
MySQL為什麼用B+樹結構?和其他結構比的優點
b+樹矮胖,查詢速度更快,且適合範圍查詢
為什麼 MysSQL 不用 跳錶
B+樹的高度在3層時儲存的資料可能已達千萬級別,但對於跳錶而言同樣去維護千萬的資料量那麼所造成的跳錶層數過高而導致的磁碟io次數增多,也就是使用B+樹在儲存同樣的資料下磁碟io次數更少
建立聯合索引時需要注意什麼
區分度大的欄位排在前面
聯合索引ABC,現在有個執行語句是A = XXX and C < XXX,索引怎麼走
根據最左匹配原則,A可以走聯合索引,C不會走聯合索引,但是C可以走索引下推
聯合索引(a,b,c) ,查詢條件 where b > xxx and a = x 會生效嗎
索引會生效,a 和 b 欄位都能利用聯合索引,符合聯合索引最左匹配原則。
聯合索引 (a, b,c),where條件是 a=2 and c = 1,能用到聯合索引嗎?
會用到聯合索引,但是隻有 a 才能走索引,c 無法走索引,因為不符合最左匹配原則。雖然 c 無法走索引, 但是 c 欄位在 5.6 版本之後,會有索引下推的最佳化,能減少回表查詢的次數
索引失效
左或者左右模糊匹配的時候,也就是 like %xx 或者 like %xx%
查詢條件中對索引列使用函式
查詢條件中索引列進行表示式計算
不遵循最左匹配原則
OR 前的條件列是索引列,而在 OR 後的條件列不是索引列
如果查詢的資料不在二級索引裡,就會先檢索二級索引,找到對應的葉子節點,獲取到主鍵值後,然後再檢索主鍵索引,就能查詢到資料了,這個過程就是回表。
覆蓋索引
一個索引包含了查詢所需的所有列
如果一個列即使單列索引,又是聯合索引,單獨查它的話先走哪個
最佳化器會選擇聯合索引,因為查詢成本更低,查詢也不需要回表,直接索引覆蓋了
索引的優缺點
佔用空間,維護時間
索引最佳化
字首索引最佳化,覆蓋索引最佳化,主鍵索引最好是自增,防止索引失效
事務的特性是什麼
ACID:原子性,一致性,隔離性,永續性
永續性是透過 redo log (重做日誌)來保證的;
原子性是透過 undo log(回滾日誌) 來保證的;
隔離性是透過 MVCC(多版本併發控制) 或鎖機制來保證的;
一致性則是透過永續性+原子性+隔離性來保證;
mysql可能出現什麼和併發相關問題
髒讀:讀到未提交
不可重複讀:讀不出相同資料
幻讀:讀數量不一致
怎麼解決併發問題
鎖+MVCC
隔離級別
讀未提交(read uncommitted)
讀提交(read committed)
可重複讀(repeatable read)
序列化(serializable)
mysql預設級別是什麼?
可重複讀隔離級別
序列化隔離級別是透過什麼實現的?
是透過行級鎖來實現的,序列化隔離級別下,普通的 select 查詢是會對記錄加 S 型的 next-key 鎖,其他事務就沒沒辦法對這些已經加鎖的記錄進行增刪改操作了,從而避免了髒讀、不可重複讀和幻讀現象。
MVCC實現原理
「讀提交」隔離級別是在「每個select語句執行前」都會重新生成一個 Read View;
「可重複讀」隔離級別是執行第一條select時,生成一個 Read View,然後整個事務期間都在用這個 Read View
Read View 有四個重要的欄位:m_ids(「活躍事務」的事務 id 列表) ,min_trx_id(活躍事務」中事務 id 最小的事務),max_trx_id(下一個事務的 id 值),creator_trx_id(該 Read View 的事務的事務 id)
InnoDB 儲存引擎的資料庫表,它的聚簇索引記錄中都包含下面兩個隱藏列
trx_id(該事務的事務 id),roll_pointer(指向每一箇舊版本記錄指標)
MySQL鎖
全域性鎖,透過flush tables with read lock 語句會將整個資料庫就處於只讀,全域性鎖主要應用於做全庫邏輯備份
表級鎖
表鎖,lock tables限制讀寫
後設資料鎖,,對一張表進行 CRUD 操作時,加的是 MDL 讀鎖;對一張表做結構變更操作的時候,加的是 MDL 寫鎖
意向鎖,對錶加上「意向獨佔鎖」,然後對該記錄加獨佔鎖。意向鎖的目的是為了快速判斷表裡是否有記錄被加鎖
行級鎖,
記錄鎖,鎖記錄,分s,x實現讀寫互斥,寫寫互斥
間隙鎖,只存在於可重複讀,為了解決換讀
臨鍵鎖,鎖住一個範圍
表鎖作用
整體控制,粒度大,適用於大批次操作
行鎖
細粒度控制,減少鎖衝突,適用於頻繁單行操作
MySQL兩個執行緒的update語句同時處理一條資料,會阻塞
兩條update語句處理一張表的不同的主鍵範圍的記錄,一個<10,一個>15,不會阻塞
如果2個範圍不是主鍵或索引,走全表掃描,會阻塞
日誌檔案
redo log 重做日誌,永續性
undo log 回滾日誌,原子性
bin log 二進位制日誌,用於資料備份和主從複製;
relay log 中繼日誌,用於主從複製場景下,slave透過io執行緒複製master的bin log後本地生成的日誌
慢查詢日誌
binlog
更新操作時會生成binlog,等事務提交時全部追加進日誌,寫滿了新開一個寫,binlog 檔案是記錄了所有資料庫表結構變更和表資料修改的日誌,不會記錄查詢類的操作
binlog 有 3 種格式型別,分別是 STATEMENT(預設格式)、ROW、 MIXED,區別如下
statement記錄sql,邏輯日誌
row記錄最後資料
mixd是兩者混合
UndoLog日誌的作用
撤銷回退,保證原子性,記錄相反語句
為什麼有redolog
保證永續性,bufferpool總是不可靠的, MySQL 的寫操作並不是立刻寫到磁碟上,而是先寫日誌,然後在合適的時間再寫到磁碟上(WAL),MySQL 重啟後,可以根據 redo log 的內容,將所有資料恢復到最新的狀態
redolog順序寫更快
能不能只用binlog不用relo log
不行,binlog是 server 層的日誌,沒辦法記錄哪些髒頁還沒有刷盤,redolog 是儲存引擎層的日誌,可以記錄哪些髒頁還沒有刷盤,
binlog 兩階段提交過程
update語句的具體執行過程
執行器負責具體執行
如果記錄不在 buffer pool,將資料頁從磁碟讀入到 buffer pool
如果一樣的話就不進行後續更新流程,否則交給innodb層完成後續
開啟事務,記錄undolog,同時記錄該redolog
更新記憶體,寫入redolog,WAL
事務提交
mysql的explain
explain 是檢視 sql 的執行計劃,主要用來分析 sql 語句的執行過程
possible_keys 欄位表示可能用到的索引;
key 欄位表示實際用的索引,如果這一項為 NULL,說明沒有使用索引;
key_len 表示索引的長度;
rows 表示掃描的資料行數。
type 表示資料掃描型別,我們需要重點看這個。
常見掃描型別
All(全表掃描)
index(全索引掃描)
range(索引範圍掃描)
ref(非唯一索引掃描)
eq_ref(唯一索引掃描)
const(結果只有一條的主鍵或唯一索引掃描)
extra 顯示的結果
Using filesort
Using temporary
Using index
發現查詢速度很慢,你有那些解決方案
分析查詢語句,建立或最佳化索引,避免索引失效,查詢最佳化,分頁最佳化,最佳化資料庫表,使用快取技術
Explain用到的索引不正確的話,有什麼辦法干預嗎?
可以使用 force index,強制走索引
MySQL 叢集的主從複製過程
寫入 Binlog:主庫寫 binlog 日誌,提交事務,並更新本地儲存資料。
同步 Binlog:把 binlog 複製到所有從庫上,每個從庫把 binlog 寫到暫存日誌中。
回放 Binlog:回放 binlog,並更新儲存引擎中的資料
主從延遲都有什麼處理方法
強制走主庫方案
分表和分庫是什麼
垂直:拆功能
水平:拆資料量