基礎(chǔ)模塊
1. MySQL執(zhí)行一條查詢語句的內(nèi)部執(zhí)行過程
客戶端先通過連接器連接到MySQL服務(wù)器;
連接器權(quán)限驗(yàn)證通過后,先查詢是否有查詢緩存 ,如果有緩存(之前執(zhí)行過此語句),則直接返回緩存數(shù)據(jù),如果沒有緩存則進(jìn)入分析器;
分析器會(huì)對(duì)產(chǎn)訊語句進(jìn)行語法分析和詞法分析,判斷SQL語法是否正確,如果查詢語法錯(cuò)誤,會(huì)直接返回給客戶端錯(cuò)誤信息,如果語法正確則進(jìn)入優(yōu)化器;
優(yōu)化器是對(duì)查詢語句進(jìn)行優(yōu)化處理,例如一個(gè)表里有多個(gè)索引,優(yōu)化器會(huì)判別哪個(gè)索引性能更好;
優(yōu)化器執(zhí)行完,就進(jìn)入執(zhí)行器,執(zhí)行器就開始執(zhí)行語句進(jìn)行查詢對(duì)比了,直到查詢到滿足條件的所有數(shù)據(jù),然后進(jìn)行返回。
2. MySQL提示“不存在此列”是執(zhí)行到了哪一個(gè)節(jié)點(diǎn)報(bào)出的
- 此錯(cuò)誤是執(zhí)行到分析器階段報(bào)出的,因?yàn)镸ySQL會(huì)在分析器階段檢查SQL語句的正確性。
3. MySQL查詢緩存的功能有何優(yōu)缺點(diǎn)
查詢緩存是在連接器之后發(fā)生的,優(yōu)點(diǎn)是效率高,如果有緩存就會(huì)直接返回結(jié)果;
查詢緩存的缺點(diǎn)是失效太頻繁導(dǎo)致緩存命中率比較低,任何更新表操作都會(huì)清空查詢緩存,因此導(dǎo)致查詢緩存非常容易失效。
4. 如何關(guān)閉MySQL的查詢緩存功能
MySQL的查詢緩存功能默認(rèn)是開啟的,配置
query cache type參數(shù)為DEMAND(按需使用)關(guān)閉查詢緩存;MySQL8.0之后直接刪除了查詢緩存的功能
5. MySQL常用的引擎有哪些
InnoDB --- 5.5.5版本后InnoDB就稱為了默認(rèn)的存儲(chǔ)引擎;
MyISAM
Memory
6. MySQL可以針對(duì)表級(jí)別設(shè)置數(shù)據(jù)庫引擎嗎?怎么設(shè)置?
- 可以針對(duì)不同的表設(shè)置不同的引擎,在
create table語句中使用engine=引擎名(比如Memory)來設(shè)置此表的存儲(chǔ)引擎:
create table student(
id int primary key auto_increment,
username varchar(120),
age int
) ENGINE=Memory
7. 常用的存儲(chǔ)引擎InnoDB和MyISAM有什么區(qū)別
-
InnoDB和 MyISAM區(qū)別:
InnoDB支持事務(wù),而MyISAM不支持事務(wù)(最大的區(qū)別);
InnoDB支持崩潰后安全恢復(fù),MyISAM不支持崩潰后安全恢復(fù);
InnoDB支持行級(jí)鎖,MyISAM不支持行級(jí)鎖,只支持到表級(jí)鎖;
InnoDB支持外鍵,MyISAM不支持外鍵;
MyISAM性能比InnoDB高;
MyISAM支持FULLTEXT類型的全文索引,InnoDB不支持FULLTEXT類型的全文索引,但是InnoDB可以使用sphinx插件支持全文索引,并且效果更好;
InnoDB 主鍵查詢性能高于 MyISAM。
8. InnoDB有哪些特性
-
插入緩存(insert buffer):
對(duì)于非聚集索引的插入和更新,不是每一次直接插入索引頁中,而是首先判斷插入的非聚集索引頁是否在緩沖池中,如果在,則直接插入,否則,先放入一個(gè)插入緩沖區(qū)中。
好似欺騙數(shù)據(jù)庫這個(gè)非聚集的索引已經(jīng)插入到葉子節(jié)點(diǎn)了,然后再以一定的頻率執(zhí)行插入緩沖和非聚集索引子節(jié)點(diǎn)的合并操作,這時(shí)通常能將多個(gè)插入合并到一個(gè)操作中,這就大大提高了對(duì)非聚集索引執(zhí)行插入和修改操作的性能。
-
**兩次寫(double write): **
兩次寫給InnoDB 帶來的是可靠性,主要用來解決部分寫失敗(partial page write)
double write有兩部分組成,一部分是內(nèi)存中的double write buffer,大小為2M;另外一部分就是物理磁盤上的共享表空間中連續(xù)的128個(gè)頁,即兩個(gè)區(qū),大小同樣為2M。
當(dāng)緩沖池的作業(yè)刷新時(shí),并不直接寫硬盤,而是通過memcpy函數(shù)先將贓頁先拷貝到內(nèi)存中的double write buffer, 之后通過double write buffer再分兩次寫,每次寫入1M到共享表空間的物理磁盤上,然后馬上調(diào)用fsync函數(shù),同步磁盤。如下圖:

- 自適應(yīng)哈希索引(adaptive hash index):由于 InnoDB 不支持 hash 索引,但在某些情況下 hash 索引的效率很高,于是出現(xiàn)了 adaptive hash index 功能, InnoDB 存儲(chǔ)引擎會(huì)監(jiān)控對(duì)表上索引的查找,如果觀察到建立 hash 索引可以提高性能的時(shí)候,則自動(dòng)建立 hash 索引。
9. 一張自增表中有三條數(shù)據(jù),刪除了兩條數(shù)據(jù)之后重啟數(shù)據(jù)庫,再新增一條數(shù)據(jù),此時(shí)這條數(shù)據(jù)的 ID 是幾
- 如果這張表的引擎是 MyISAM,那么 ID=4,如果是 InnoDB,如果是MySQL 8 之前的版本那么 ID=2,
如果是MySQL 8 之后的版本,那么ID=4
10. MySQL中什么情況會(huì)導(dǎo)致自增主鍵不能連續(xù)
唯一主鍵沖突會(huì)導(dǎo)致自增鍵不連續(xù)
事務(wù)回滾也會(huì)導(dǎo)致自增鍵不連續(xù)
11. InnoDB中自增主鍵能不能被持久化
自增主鍵能不能被持久化,說的是MySQL重啟之后InnoDB能不能恢復(fù)重啟之前的自增列;
InnoDB在8.0之前是沒有持久化能力的,但MySQL8.0之后就把自增主鍵保存到redo log(一種日志類型)中,當(dāng)MySQL重啟之后就會(huì)從redo log 日志中恢復(fù);
12. 什么是獨(dú)立表空間和共享表空間,他們的區(qū)別是什么
共享表空間: 指的是數(shù)據(jù)庫的所有表數(shù)據(jù),索引文件全部放在一個(gè)文件中,默認(rèn)這個(gè)共享表空間的文件路徑在data目錄下
獨(dú)立表空間: 每一個(gè)表都將會(huì)生成以獨(dú)立的文件方式來進(jìn)行存儲(chǔ);
區(qū)別: 最大的區(qū)別是如果把表放在共享表空間,即使表刪除了,空間也不會(huì)刪除,所以表依然很大,而獨(dú)立表空間如果刪除表就會(huì)清除空間。
13. 如何設(shè)置獨(dú)立表空間
- 獨(dú)立表空間是由參數(shù)
innodb*file*per_table控制的,把它設(shè)置成 ON 就是獨(dú)立表空間了,從 MySQL 5.6.6 版本之后,這個(gè)值就默認(rèn)是 ON 了。
14. 如何進(jìn)行表空間收縮
使用重建表的方式可以收縮表空間,重建表有一下三種方式
alter table t engine=InnoDB
optmize table t
truntace table t
15. 說一下重建表的執(zhí)行流程
建立一個(gè)臨時(shí)文件,掃描表t主鍵的所有數(shù)據(jù)頁;
用數(shù)據(jù)頁中表t的記錄生成B+樹,存儲(chǔ)到臨時(shí)文件中;
生成臨時(shí)文件的過程中,將所有對(duì)t的操作記錄在一個(gè)日志文件(row log)中;
臨時(shí)文件生成后,將日志文件中的操作應(yīng)用到臨時(shí)文件,得到一個(gè)邏輯上與表t相同的數(shù)據(jù)文件;
用臨時(shí)文件替換表t的數(shù)據(jù)文件
16. 表的結(jié)構(gòu)信息存在哪里
表結(jié)構(gòu)定義占有的存儲(chǔ)空間比較小
MySQL8之前,表結(jié)構(gòu)的定義信息存在以.frm為后綴的文件里;
MySQL8之后,則允許把表結(jié)構(gòu)的定義信息存在系統(tǒng)數(shù)據(jù)表之中;
17. 什么是覆蓋索引
覆蓋索引是指,索引上的信息足夠滿足查詢請(qǐng)求,不需要再回到主鍵上去取數(shù)據(jù)
18. 如果把一個(gè)InnoDB表的主鍵刪掉,是不是就沒有主鍵,就沒有辦法進(jìn)行回表查詢了
可以回表查詢,如果把主鍵刪掉了,那么InnoDB會(huì)自己生成一個(gè)長度為6字節(jié)的rowid作為主鍵;
19. 執(zhí)行一個(gè) update 語句以后,我再去執(zhí)行 hexdump 命令直接查看 ibd 文件內(nèi)容,為什么沒有看到數(shù)據(jù)有改變呢
可能是因?yàn)?update 語句執(zhí)行完成后,InnoDB 只保證寫完了 redo log,內(nèi)存中的數(shù)據(jù)可能還沒來得及將數(shù)據(jù)寫到磁盤。
20. 內(nèi)存表和臨時(shí)表有什么區(qū)別?
-
**內(nèi)存表: **
指的是使用 Memory 引擎的表,建表語法是 create table … engine=memory;
內(nèi)存表的數(shù)據(jù)都保存在內(nèi)存里,系統(tǒng)重啟的時(shí)候會(huì)被清空,但是表結(jié)構(gòu)還在;
-
臨時(shí)表:
可以使用各種引擎類型
如果是使用 InnoDB 引擎或者 MyISAM 引擎的臨時(shí)表,寫數(shù)據(jù)的時(shí)候是寫到磁盤上的。
21. 并發(fā)事務(wù)會(huì)帶來哪些問題
臟讀
修改丟失
不可重復(fù)讀
幻讀
22. 什么是臟讀,幻讀和不可重復(fù)讀
臟讀: 指當(dāng)一個(gè)事務(wù)正在訪問數(shù)據(jù),并且對(duì)數(shù)據(jù)進(jìn)行了修改,而這種修改還沒有提交到數(shù)據(jù)庫中,這時(shí),另外一個(gè)事務(wù)也訪問這個(gè)數(shù)據(jù),然后使用了這個(gè)數(shù)據(jù)。
幻讀(針對(duì)insert和delete操作): 是指當(dāng)事務(wù)不是獨(dú)立執(zhí)行時(shí)發(fā)生的一種現(xiàn)象,例如第一個(gè)事務(wù)對(duì)一個(gè)表中的數(shù)據(jù)進(jìn)行了修改,這種修改涉及到表中的全部數(shù)據(jù)行。同時(shí),第二個(gè)事務(wù)也修改這個(gè)表中的數(shù)據(jù),這種修改是向表中插入一行新數(shù)據(jù)。那么,以后就會(huì)發(fā)生操作第一個(gè)事務(wù)的用戶發(fā)現(xiàn)表中還有沒有修改的數(shù)據(jù)行,就好象發(fā)生了幻覺一樣。
不可重復(fù)讀(針對(duì)insert與update操作): 是指在一個(gè)事務(wù)內(nèi),多次讀同一數(shù)據(jù)。在這個(gè)事務(wù)還沒有結(jié)束時(shí),另外一個(gè)事務(wù)也訪問該同一數(shù)據(jù)。那么,在第一個(gè)事務(wù)中的兩次讀數(shù)據(jù)之間,由于第二個(gè)事務(wù)的修改,那么第一個(gè)事務(wù)兩次讀到的的數(shù)據(jù)可能是不一樣的。這樣在一個(gè)事務(wù)內(nèi)兩次讀到的數(shù)據(jù)是不一樣的,因此稱為是不可重復(fù)讀。
**臟讀、幻讀、不可重復(fù)讀: ** https://blog.csdn.net/qq_33591903/article/details/81672260
23. 為什么會(huì)出現(xiàn)幻讀,幻讀帶來的問題,以及避免
https://blog.csdn.net/andyxm/article/details/44810417 (幻讀和間隙鎖)
原因: 因?yàn)樾墟i只能鎖定存在的行,針對(duì)新插入的操作沒有限定,所以就有可能產(chǎn)生幻讀
-
問題:
對(duì)行鎖語義的破壞
破壞了數(shù)據(jù)一致性
如何避免幻讀
使用間隙鎖的方式來避免出現(xiàn)幻讀。
間隙鎖,是專門用于解決幻讀這種問題的鎖,它鎖的了行與行之間的間隙,能夠阻塞新插入的操作 間隙鎖的引入也帶來了一些新的問題,比如:降低并發(fā)度,可能導(dǎo)致死鎖。
24. 如何查看 MySQL 的空閑連接?
在 MySQL 的命令行中使用 show processlist; 查看所有連接,其中 Command 列顯示為 Sleep 的表示空閑連接
25. MySQL 中的字符串類型都有哪些
| 類型 | 取值范圍 |
| :----------: | :-----------------------: |
| CHAR(N) | 0~255 |
| VARCHAR(N) | 0~65536 |
| TINYBLOB | 0~255 |
| BLOB | 0~65535 |
| MEDUIMBLOB | 0~167772150 |
| LONGBLOB | 0~4294967295 |
| TINYTEXT | 0~255 |
| TEXT | 0~65535 |
| MEDIUMTEXT | 0~167772150 |
| LONGTEXT | 0~4294967295 |
| VARBINARY(N) | 0~N個(gè)字節(jié)的變長字節(jié)字符集 |
| BINARY(N) | 0~N個(gè)字節(jié)的定長字節(jié)字符集 |
26. VARCHAR 和 CHAR 的區(qū)別是什么?分別適用的場景有哪些?
VARCHAR 的長度是可變的,而 CHAR 是固定長度,CHAR 的取值范圍為1-255,因此 VARCHAR 可能會(huì)造成存儲(chǔ)碎片。
由于它們的特性決定了 CHAR 比較適合長度較短的字段和固定長度的字段,如身份證號(hào)、手機(jī)號(hào)等,反之則適合使用 VARCHAR。
27. MySQL 存儲(chǔ)金額應(yīng)該使用哪種數(shù)據(jù)類型?為什么?
MySQL 存儲(chǔ)金額應(yīng)該使用 decimal ,因?yàn)槿绻鎯?chǔ)其他數(shù)據(jù)類型,比如 float 有導(dǎo)致小數(shù)點(diǎn)后數(shù)據(jù)丟失的風(fēng)險(xiǎn)。
28. limit 3,2 的含義是什么?
去除前三條數(shù)據(jù)之后查詢兩條信息。
29. now() 和 current_date() 有什么區(qū)別?
now() 返回當(dāng)前時(shí)間包含日期和時(shí)分秒,current_date() 只返回當(dāng)前時(shí)間
30. 如何去重計(jì)算總條數(shù)?
使用 distinct 去重,使用 count 統(tǒng)計(jì)總條數(shù),具體實(shí)現(xiàn)腳本如下:
select count(distinct f) from t
31. last_insert_id()函數(shù)功能是什么?有什么特點(diǎn)?
用于查詢最后一次自增表的編號(hào),它的特點(diǎn)是查詢時(shí)不需要指定表名,使用
select last_insert_id()即可查詢,因?yàn)椴恍枰付ū砻运冀K以最后一條自增編號(hào)為主,可以被其它表的自增編號(hào)覆蓋。比如 A 表的最大編號(hào)是 10,lastinsertid() 查詢出來的值為 10,這時(shí) B 表插入了一條數(shù)據(jù),它的最大編號(hào)為 3,這個(gè)時(shí)候使用 lastinsertid() 查詢的值就是 3。
32. 刪除表的數(shù)據(jù)有幾種方式?它們有什么區(qū)別?
-
刪除數(shù)據(jù)有兩種方式:delete 和 truncate ,它們的區(qū)別如下:
delete 可以添加 where 條件刪除部分?jǐn)?shù)據(jù),truncate 不能添加 where 條件只能刪除整張表;
delete 的刪除信息會(huì)在 MySQL 的日志中記錄,而 truncate 的刪除信息不被記錄在 MySQL 的日志中,因此 detele 的信息可以被找回而 truncate 的信息無法被找回;
truncate 因?yàn)椴挥涗浫罩舅詧?zhí)行效率比 delete 快。
delete 和 truncate 的使用腳本如下:
delete from t where username='redis';
truncate table t;
33. MySQL 中支持幾種模糊查詢?它們有什么區(qū)別?
MySQL 中支持兩種模糊查詢:regexp 和 like
-
區(qū)別:
like 是對(duì)任意多字符匹配或任意單字符進(jìn)行模糊匹配,而 regexp 則支持正則表達(dá)式的匹配方式,提供比 like 更多的匹配方式
示例
select * from person where uname like '%SQL%'; select from person where uname regexp '.SQL*.';
34. MySQL 支持枚舉嗎?如何實(shí)現(xiàn)?它的用途是什么?
- MySQL 支持枚舉,它的實(shí)現(xiàn)方式如下:
create table t(
sex enum('boy','grid') default 'unknown'
);
- 枚舉的作用是預(yù)定義結(jié)果值,當(dāng)插入數(shù)據(jù)不在枚舉值范圍內(nèi),則插入失敗,提示錯(cuò)誤
Data truncated for column 'xxx' at row n
35. count(column) 和 count(*) 有什么區(qū)別?
count(column) 和 count() 最大區(qū)別是統(tǒng)計(jì)結(jié)果可能不一致:
count(column) 統(tǒng)計(jì)不會(huì)統(tǒng)計(jì)列值為 null 的數(shù)據(jù)
count() 則會(huì)統(tǒng)計(jì)所有信息
36. 以下關(guān)于 count 說法正確的是?
count 的查詢性能在各種存儲(chǔ)引擎下的性能都是一樣的。(錯(cuò)誤)
count 在 MyISAM 比 InnoDB 的性能要低。(錯(cuò)誤)
count 在 InnoDB 中是一行一行讀取,然后累計(jì)計(jì)數(shù)的。 (正確)
count 在 InnoDB 中存儲(chǔ)了總條數(shù),查詢的時(shí)候直接取出。(錯(cuò)誤)
37. 為什么 InnoDB 不把總條數(shù)記錄下來,查詢的時(shí)候直接返回呢?
因?yàn)?InnoDB 使用了事務(wù)實(shí)現(xiàn),而事務(wù)的設(shè)計(jì)使用了多版本并發(fā)控制,即使是在同一時(shí)間進(jìn)行查詢,得到的結(jié)果也可能不相同,所以 InnoDB 不能把結(jié)果直接保存下來,因?yàn)檫@樣是不準(zhǔn)確的。
38. 能否使用 show table status 中的表行數(shù)作為表的總行數(shù)直接使用?為什么?
不能,因?yàn)?show table status 是通過采樣統(tǒng)計(jì)估算出來的,官方文檔說誤差可能在 40% 左右,所以 show table status 中的表行數(shù)不能直接使用
39. 以下哪個(gè) SQL 的查詢性能最高?
select count(*) from t where time>1000 and time<4500 ;
show table status where name='t' ;
select count(id) from t where time>1000 and time<4500 ;
select count(name) from t where time>1000 and time<4500;
第二條性能最高;
題目解析:因?yàn)?show table status 的表行數(shù)是估算出來,而其他的查詢因?yàn)樘砑恿?where 條件,即使是 MyISAM 引擎也不能直接使用已經(jīng)存儲(chǔ)的總條數(shù),所以 show table status 的查詢性能最高。
40. InnoDB 和 MyISAM 執(zhí)行 select count(*) from t,哪個(gè)效率更高?為什么?
MyISAM 效率最高,因?yàn)?MyISAM 內(nèi)部維護(hù)了一個(gè)計(jì)數(shù)器,直接返回總條數(shù),而 InnoDB 要逐行統(tǒng)計(jì)
41. 在 MySQL 中有對(duì) count(*)做優(yōu)化嗎?做了哪些優(yōu)化?
MySQL 有對(duì) count() 進(jìn)行優(yōu)化,以 InnoDB 為例:
在 InnoDB 中主鍵索引數(shù)的葉子節(jié)點(diǎn)是主鍵值,而普通索引的葉子節(jié)點(diǎn)則是主鍵值,所以普通索引數(shù)比主鍵索引數(shù)要小很多,
而對(duì)于 count 查詢來說,每個(gè)索引樹的查詢結(jié)果都是一樣的,所以 MySQL 會(huì)選擇最小的那顆樹來遍歷,以此來優(yōu)化 count() 的查詢。
42. 在 InnoDB 引擎中 count(*)、count(1)、count(主鍵)、count(字段) 哪個(gè)性能最高?
count(字段)<count(主鍵 id)<count(1)≈count(*) :
對(duì)于 count(主鍵 id) 來說,InnoDB 引擎會(huì)遍歷整張表,把每一行的 id 值都取出來,返回給 server 層。server 層拿到 id 后,判斷是不可能為空的,就按行累加。
對(duì)于 count(1) 來說,InnoDB 引擎遍歷整張表,但不取值。server 層對(duì)于返回的每一行,放一個(gè)數(shù)字“1”進(jìn)去,判斷是不可能為空的,按行累加。
對(duì)于 count(字段) 來說,如果這個(gè)“字段”是定義為 not null 的話,一行行地從記錄里面讀出這個(gè)字段,判斷不能為 null,按行累加;如果這個(gè)“字段”定義允許為 null,那么執(zhí)行的時(shí)候,判斷到有可能是 null,還要把值取出來再判斷一下,不是 null 才累加。
對(duì)于
count(*)來說,并不會(huì)把全部字段取出來,而是專門做了優(yōu)化,不取值。count(*)肯定不是 null,按行累加。
43. MySQL 中內(nèi)連接、左連接、右連接有什么區(qū)別?
內(nèi)連(inner join)-------把匹配的關(guān)聯(lián)數(shù)據(jù)顯示出來;
左連接(left join) ------把左邊的表全部顯示出來,右邊的表顯示出符合條件的數(shù)據(jù);
右連接(right join) ------把右邊的表全部顯示出來,左邊的表顯示出符合條件的數(shù)據(jù);
44. 什么是視圖?如何創(chuàng)建視圖?
視圖是一種虛擬的表,具有和物理表相同的功能,可以對(duì)視圖進(jìn)行增、改、查操作。視圖通常是一個(gè)表或者多個(gè)表的行或列的子集。 視圖創(chuàng)建腳本如下:
create view vname as
select column_names
from table_name
where condition
45. 視圖有哪些優(yōu)點(diǎn)?
獲取數(shù)據(jù)更容易,相對(duì)于多表查詢來說;
視圖能夠?qū)C(jī)密數(shù)據(jù)提供安全保護(hù);
視圖的修改不會(huì)影響基本表,提供了獨(dú)立的操作單元,比較輕量。
46. MySQL 中“視圖”的概念有幾個(gè)?分別代表什么含義?
MySQL 中的“視圖”概念有兩個(gè),它們分別是:
MySQL 中的普通視圖也是我們最常用的 view,創(chuàng)建語法是 create view ...,它的查詢和普通表一樣;
InnoDB 實(shí)現(xiàn) MVCC(Multi-Version Concurrency Control)多版本并發(fā)控制時(shí)用到的一致性讀視圖,它沒有物理結(jié)構(gòu),作用是事務(wù)執(zhí)行期間定于可以看到的數(shù)據(jù)。
47. 使用 delete 誤刪數(shù)據(jù)怎么找回?
可以用 Flashback 工具通過閃回把數(shù)據(jù)恢復(fù)回來。
48. Flashback 恢復(fù)數(shù)據(jù)的原理是什么?
Flashback 恢復(fù)數(shù)據(jù)的原理是是修改 binlog 的內(nèi)容,拿回原庫重放,從而實(shí)現(xiàn)數(shù)據(jù)找回。