# mysql百問
!(## mysql有哪些模組
!(## mysql儲存引擎有哪些
主要有這些儲存引擎: `myisam`,`innodb`,`memory`,`archive`
`memory`是儲存到記憶體中,重啟後資料會丟失,不太常用。
`archive`用作歸檔, 可以儲存更多資料,基本不會用作線上環境的查詢。
`myisam` 是mysql之前版本使用的預設儲存引擎(後來變更為innodb),它不支援事務,只支援表鎖,沒有crash-safe的能力,所以慢慢會被淘汰掉
`innodb`是mysql的預設引擎,效能不錯,同時支援事務、行鎖、表鎖能力。是日常開發首選的儲存引擎。
## mysql的隔離級別
主要分為: `read-uncommitted(讀未提交)`,`read-committed(讀已提交)`,`repeatable-read(可重複讀)`,`serializable(序列化)`,這也是sql標準的四種隔離級別
- `read-uncommitted`: 乙個事務修改了內容沒有提交,別的事務也能看到修改。完全沒有事務控制,線上環境基本不用。
- `serializable`: 對於同一行資料,寫會加寫鎖,讀會加讀鎖,排隊讀取(修改)資源,修改絕對安全,但效率低下,基本不用。
- `read-committed`: 事務裡面修改的資料,只有提交後,其他事務才能看到。
- `repeatable-read`: 開啟乙個事務後,讀取到資料不會受其他事務影響,即使別的事務修改了資料,該事務還是讀取的之前的資料。
`oracle`預設使用 `read-committed`隔離級別,而`mysql`使用的是`repeatable-read`,[[
## 幻讀、髒讀、不可重複讀
在多事務併發情況下,使用不同的隔離級別會產生不同的問題: `幻讀`、`髒讀`、`不可重複讀`
- `幻讀`: a事務隔了10秒查詢了兩次資料,b事務在這10秒內插入並提交了資料導致a事務兩次查詢結果不一致,稱為幻讀。(幻讀專指新插入的資料導致的不一致)
- `髒讀`:a事務修改了某個值被b事務讀取到了,這個時候a事務回滾了,但是b還是使用了那個錯誤的資料
- `不可重複讀`: a事務讀取了a=1,b事務修改了a=2並提交事務,然後a事務再讀的時候就是a=2
## mvcc事務控制如何理解
mvcc保證了資料的查詢一致性, 無論資料被修改多少次都可以通過回溯拿到事務開啟那刻的資料值。
## redo log、binlog、undo log
`redo log` 是innodb獨有,主要作用有兩個:
1. 乙個是用於提高資料修改效率(不用每次都更新到硬碟裡面)
2. 保證了`crash-safe`能力,在異常啟動後, 不會導致資料丟失。
`redo log`有乙個固定大小的空間,迴圈寫入。
!(`binlog` 是所有引擎都有的,主要用於資料歸檔, 可以記錄長時間的資料變動,同時可以用於主從複製。
## 兩階段提交
兩階段提交指的是innodb在更新資料時,先將變動寫入`redo log` 同時將狀態變更為 `prepare` 狀態,然後寫入`binlog`,再將`redo log`狀態變更為 `commit` 狀態。
為什麼要兩階段提交? 為了保證寫入 `redo log` 的資料和寫入`binlog`的資料是一致的,對於從庫的資料同步很重要。
!(如果寫入過程中, redo log處於prepare狀態, binlog已經寫完,在更新redo log為commit狀態時,斷電了會怎麼辦?
啟動後, redo log依然是prepare狀態, 這個時候會去檢查binlog,來判斷這個redo log能否commit。
理論上來說只使用binlog也能完成crash-safe, 為什麼沒實現呢?
1. 歷史原因, 從開始設計的時候,就沒有用binlog來實現crash-safe
2. binlog可以關閉的
13.commit操作,由於儲存引擎層與server層之間採用的是內部xa(保證兩個事務的一致性,這裡主要保證redo log和binlog的原子性),
所以提交分為prepare階段與commit階段
14.prepare階段,將事務的xid寫入,將binlog\_cache裡的進行flush以及sync操作(大事務的話這步非常耗時)
15.commit階段,由於之前該事務產生的redo log已經sync到磁碟了。所以這步只是在redo log裡標記commit
## 索引儲存的方式
索引分為主鍵索引(聚簇索引)和非主鍵索引(二級索引), 主鍵索引的葉子節點儲存的是整行資料, 非主鍵索引葉子節點儲存的是主鍵值。
!(``` mysql
create table t(
id int primary key,
k int not null,
name varchar(16),
index (k)
)engine=innodb;
如果用id(主鍵)進行查詢時,可以直接查到整行資料(只需要搜尋一棵b+tree)
``` mysql
select * from t where id=500;
如果用k(非主鍵)進行查詢時, 需要先查詢以k建立的b+樹, 拿到主鍵,再根據主鍵去查詢主鍵索引樹(需要搜尋兩棵樹)
``` mysql
select * from t where k=5
## 什麼是回表
對非主鍵索引進行查詢時,需要先使用二級索引查到對應主鍵,再拿著主鍵值去主鍵索引查詢整行資料,第二次查詢稱為回表
例如有個身份證資訊庫,需要根據身份證號查詢姓名, 就可以將身份證和姓名都加到乙個索引裡面,這樣就減少了回表操作(稱之為覆蓋索引)。
## 使用自增id做主鍵的好處
1. 二級索引的葉子節點是主鍵,如果主鍵占用空間越小,二級索引占用空間也越小
2. 主鍵是順序增加的,不會在新增的時候,造成資料頁填滿,引發分頁問題
## 主鍵超過最大值會怎麼樣
id不會繼續增加, 然後插入主鍵衝突阻止插入
## 什麼情況下可以用普通字段做主鍵
1. 普通欄位是唯一的(基本條件)
2. 只有乙個索引(不用考慮主鍵過長導致二級索引占用太多空間)
## delete操作會減少空間占用嗎
不會, delete只是標記下資料為已刪除或者標記資料頁可復用,並不會真正刪除資料。
如果需要刪除資料(innodb引擎)應該用 `alter table t engine=innodb`
## 為什麼要用innodb替代myisam
1. innodb支援事務, myisam不支援
2. innodb 有crash-safe能力
3. innodb支援行鎖, myisam只支援表鎖
4. 整表備份匯出的時候, 為了保證資料一致, innodb可以用多檢視併發模型來匯出(–single-transaction), myisam只能增加全域性讀鎖(flush tables with read lock)
(myisam原本是mysql預設的儲存引擎,innodb才是後來從外部引入的)
MySQL設計題庫
一 綜合題 25 分 關聯式資料庫中有下列三個關係 商店 商店代號,商店名,店員人數,所在城市 shop sno,sna,snu,city 商品 商品編號,商品名,goods gno,gna,price 商店 商品 商店代號,商品編號,商品數量 shop goods sno,gno,num 試用 s...
MySQL每日一題(1)
表1 person 表1 person 列名 型別 personid int firstname varchar lastname varchar personid 是上表主鍵表2 address 列名 型別 addressid int personid int city varchar state...
MySQL聚合函式,多表題庫,帶分析思路
1.列表內容 部門表 create table dept id int primary key primary key,部門id dname varchar 50 部門名稱 loc varchar 50 部門所在地 新增4個部門 insert into dept id,dname,loc value...