面試準備:數據庫常見面試題彙總

1.簡單解釋數據庫三範式?

第一範式就是數據庫表的每一列都是不可分割的基本數據項,同一列中不能有多個值

第二範式要求實體的屬性完全依賴於主關鍵字(即不存在部分依賴)。所謂完全依賴是指不能存在僅依賴主關鍵字一部分的屬性,如果存在,那麼這個屬性和主關鍵字的這一部分應該分離出來形成一個新的實體

第三範式要求一個數據庫表中不包含已在其它表中已包含的非主關鍵字信息(即消除傳遞依賴)。
例如,存在一個部門信息表,其中每個部門有部門編號(dept_id)、部門名稱、部門簡介等信息。那麼在員工信息表中列出部門編號後就不能再將部門名稱、部門簡介等與部門有關的信息再加入員工信息表中。

更多知識點,參考:高性能Mysql——範式與反範式

2.不滿足數據庫三範式可能會出現什麼情況?

數據冗餘(想修改一個屬性,就要更新多行數據)
插入異常(想要插入數據,結構因爲表設計的問題,導致不能成功插入)
刪除異常(只想刪除其中的某些數據 ,結果把不該刪的也刪了)
更新異常(想更新一條數據,結果工作量大,還容易出錯)

3.解釋髒讀、不可重複讀,幻讀,更新丟失


  • 髒讀(Dirty read):在一個事務中讀取到另一個事務已經修改但沒有提交的數據。

例如,事務A對數據進行了修改,但是還沒有提交,這時事務B讀取這個數據,然後事務A回滾,那麼事務B取的數據無效。不符合一致性

解決辦法:把數據庫的事務隔離級別調整到READ_COMMITTED


  • 不可重複讀(NonRepeatable Read):不能讀到相同的數據內容,事務A讀取到了事務B已經提交的修改數據(即一個事務範圍內兩個相同的查詢卻返回了不同數據)。

例如事務A先讀取數據,然後事務B對該同一數據修改並提交,那麼事務A再次讀取該數據時,由於事務B對該數據的修改,事務A兩次讀到的的數據可能是不一樣的。不符合隔離性

解決辦法:把數據庫的事務隔離級別調整到REPEATABLE_READ


  • 幻讀(Phantom Read):事務在插入已經檢查過不存在的記錄時,驚奇的發現這些數據已經存在了(針對的insert操作) 。

在事務A查詢結束後,事務B往User表中插入了一條id爲1的數據。此時,由於事務A查詢到id爲1的用戶不存在,因此插入1條id爲1的數據,報錯:主鍵衝突。不符合隔離性。

解決辦法:把數據庫的事務隔離級別調整到SERIALIZABLE_READ


  • 更新丟失(Update lose):兩個事務同時操作相同數據,後提交的事務會覆蓋先提交的事務處理結果。

解決辦法:樂觀鎖

4. Mysql提供了哪幾種事務隔離級別?

MySQL數據的四種隔離級別:
  ① Serializable (串行化):可避免髒讀、不可重複讀、幻讀的發生。
  ② Repeatable read (可重複讀):可避免髒讀、不可重複讀的發生。
  ③ Read committed (讀已提交):可避免髒讀的發生。
  ④ Read uncommitted (讀未提交):最低級別,任何情況都無法保證。

通過SELECT @@transaction_isolation;(mysql 5.7以下是select @@tx_isolation)可以查看事務隔離級別:
在這裏插入圖片描述

隔離界別爲可重複讀,那麼我寫一個髒讀和可重複讀的事務:

# 事務A
begin;
	select * from orders where id="190827F4AK12R30H";
commit;
# 事務B
begin;
	UPDATE orders SET left_msg="new message" where id="190827F4AK12R30H";
	select sleep(10);
commit;

查詢結果是:儘管事務B修改了left_msg爲new message,但是事務A的查詢結果是old message。

# 事務A
begin;
	select * from orders where id="190827F4AK12R30H";
	select sleep(10);
	select * from orders where id="190827F4AK12R30H";
commit;

# 事務B
begin;
	UPDATE orders SET left_msg="new message" where id="190827F4AK12R30H";
commit;

查詢結果是:儘管事務B修改了left_msg爲new message,但是兩次事務A的查詢結果都是 old message。

最後試試幻讀:

# 事務A
begin;
	select * from stu where id=1;
	select sleep(10);
	insert into stu(id,name,age) values (1,"xiaoming",13);
commit;
# 事務B
begin;
	insert into stu(id,name,age) values (1,"xiaohong",15);
commit;

運行結果:
在這裏插入圖片描述
可把事務級別改成串行set session transaction isolation level SERIALIZABLE;
使用set session transaction isolation level REPEATABLE READ;改回來

5.MySQL中varchar與char的區別?

CHAR和VARCHAR最大的不同就是一個是固定長度,一個是可變長度。
CHAR存儲定長數據很方便,CHAR字段上的索引效率級高,比如定義 char(10),那麼不論你存儲的數據是否達到了10個字節,都要佔去10個字節的空間,不足的自動用空格填充(並且如果存儲的char類型的字符串後面有空格的話,innodb會忽略)。
VARCHAR值保存時只保存需要的字符數,另加一個字節來記錄長度(如果列聲明的長度超過255,則 使用兩個字節)。

一般來說,CHAR比VARCHAR更快,因爲CHAR是固定長度的,而VARCHAR需要增加一個長度標識,處理時需要多一次運算。但是有例外,參考:MySQL Innodb數據庫性能實踐——VARCHAR vs CHAR,但是如果使用的是Innodb引擎的話,推薦使用varchar代替char。特別是字符串的平均長度比最大長度要小很多的情況;當然,如果你的字符串本來就很短或者字符串長度固定,例如只有10個字符,那麼就優先選CHAR了。

6.MySQL中int(11)與int(3)的區別?

當我們在選擇使用int的類型的時候,不論是int(3)還是int(11),它在數據庫裏面存儲的都是4個字節的長度。

如果int的值爲10
int(11)顯示結果爲00000000010
int(3)顯示結果爲010
就是顯示的長度不一樣而已,但都是佔用四個字節的空間。

類型長度,參考:https://www.runoob.com/mysql/mysql-data-types.html。

更多知識點,參考高性能Mysql——Schema與數據類型優化

7.date,datetime和timestamp數據類型有什麼區別?

一個完整的日期格式如下:YYYY-MM-DD HH:MM:SS[.fraction],它可分爲兩部分:date部分和time部分,其中,date部分對應格式中的“YYYY-MM-DD”,time部分對應格式中的“HH:MM:SS[.fraction]”。對於date字段來說,它只支持date部分,如果插入了time部分的內容,它會丟棄掉該部分的內容,並提示一個warning。

timestamp和datetime的不同點:
DATETIME 的日期範圍是 1001——9999 年;TIMESTAMP 的時間範圍是 1970——2038 年
DATETIME 存儲時間與時區無關;TIMESTAMP 存儲時間與時區有關,顯示的值也依賴於時區
DATETIME 的存儲空間爲 8 字節;TIMESTAMP 的存儲空間爲 4 字節
DATETIME 的默認值爲 null;TIMESTAMP 的字段默認不爲空(not null),默認值爲當前時間(CURRENT_TIMESTAMP)

8.union 與union all的區別

union 在進行錶鏈接後會篩選掉重複的記錄,所以在錶鏈接後會對所產生的結果集進行排 序運算,刪除重複的記錄再返回結果。 union all 則會顯示重複結果,只是簡單的兩個結果合併並返回.所以效率比union高,在保證沒有重複數據的情況下用union all.

9.各種join的區別?

參考:https://blog.csdn.net/weter_drop/article/details/84729822

10.drop,delete與truncate的區別?

  • DROP語句:
    直接刪掉表。drop語句將表所佔用的空間全釋放掉。
  • TRUNCATE語句:
    刪除表中數據,再插入時自增長id又從1開始 。當表被TRUNCATE 後,這個表和索引所佔用的空間會恢復到初始大小。 並且不會把單獨的刪除操作記錄記入日誌保存,刪除行是不能恢復的。
  • DELETE語句:
    刪除表中數據,可以加where字句,並且同時將該行的刪除操作作爲事務記錄在日誌中保存以便進行進行回滾操作。DELETE操作不會減少表或索引所佔用的空間。

delete語句爲DML(data maintain Language),這個操作會被放到 rollback segment中,事務提交後才生效。如果有相應的 tigger,執行的時候將被觸發。
truncate、drop是DLL(data define language),操作立即生效,原數據不放到 rollback segment中,不能回滾。

11.MySQL有哪幾種索引?

Mysql索引,按物理存儲的角度劃分,分爲聚集索引和非聚集索引。

聚集索引是基於B+樹的,非葉節點只做根據主鍵的索引,而由葉節點來保存主鍵記錄的指針,這樣使得B+樹每個非葉子節點所能保存的關鍵字大大增加,使得B+樹層級更少,IO操作也更少。B+樹葉子節點的關鍵字從小到大有序排列,天然具備排序功能;左邊的數據會有一個向右的指針,使得全節點遍歷更快。

如果沒有主鍵被定義,那麼該表的第一個唯一非空索引被作爲聚集索引。
如果沒有主鍵也沒有合適的唯一索引,那麼innodb內部會生成一個隱藏的主鍵作爲聚集索引。

非聚集索引和聚集索引差不多,通過聚集索引可以查到需要查找的數據, 而通過非聚集索引可以查到記錄對應的主鍵值 , 再使用主鍵的值通過聚集索引查找到需要的數據。

參考:高性能Mysql——創建高性能的索引

參考:其他索引方式

12.簡要說明InnoDB事務是如何通過日誌來實現的?

參考:Java架構直通車——InnoDB事務是如何通過日誌來實現的?

13.簡述Mysql Innodb引擎和MyIASM引擎的區別?什麼時候選擇MyIASM?

InnoDB

默認事務型引擎,被廣泛使用的存儲引擎
數據存儲在共享表空間,即多個表和索引都存儲在一個表空間中,可通過配置文件修改
主鍵查詢的性能高於其他類型的存儲引擎
內部做了很多優化,如:從磁盤讀取數據時會自動構建hash索引,插入數據時自動構建插入緩衝區
通過一些機制和工具支持真正的熱備份
支持崩潰後的安全恢復
支持行級鎖
支持外鍵

MyISAM

擁有全文索引、壓縮、空間函數
不支持事務和行級鎖、不支持崩潰後的安全恢復
表存儲在兩個文件:MYD 和 MYI
設計簡單,某些場景下性能很好,例如獲取整個表有多少條數據,性能很高

MyISAM和InnoDB的區別
InnoDB支持事務與外鍵和行級鎖,MyISAM不支持(最主要的差別)

MyISAM讀性能要優於InnoDB,除了針對索引的update操作,MyISAM的寫性能可能低於InnoDB,其他操作MyISAM的寫性能也是優於InnoDB的,而且可以通過分庫分表來提高MyISAM寫操作的速度

③MyISAM的索引和數據是分開的,而且索引是壓縮的,而InnoDB的索引和數據是緊密捆綁的,沒有使用壓縮,所以InnoDB的體積比MyISAM龐大

MyISAM引擎索引結構的葉子節點的數據域,存放的並不是實際的數據記錄,而是數據記錄的地址。索引文件與數據文件分離,這樣的索引稱爲“非聚簇索引”。其檢索算法:先按照B+Tree的檢索算法檢索,找到指定關鍵字,則取出對應數據域的值,作爲地址取出數據記錄。

InnoDB引擎索引結構的葉子節點的數據域,存放的就是實際的數據記錄。這樣的索引被稱爲“聚簇索引”,一個表只能有一個聚簇索引。

④InnoDB 中不保存表的具體行數,也就是說,執行select count() from table時,InnoDB要掃描一遍整個表來計算有多少行,但是MyISAM只要簡單的讀出保存好的行數即可。注意的是,當count()語句包含 where條件時,兩種表的操作是一樣的。

⑤DELETE FROM table時,InnoDB不會重新建立表,而是一行一行的刪除。

⑥InnoDB表的行鎖也不是絕對的,假如在執行一個SQL語句時MySQL不能確定要掃描的範圍,InnoDB表同樣會鎖全表,例如update table set num=1 where name like “%aaa%”

在where條件沒有主鍵時,InnoDB照樣會鎖全表

選擇哪種搜索引擎,應視具體應用而定

①**如果是讀多寫少的項目,**可以考慮使用MyISAM,MYISAM索引和數據是分開的,而且其索引是壓縮的,可以更好地利用內存。所以它的查詢性能明顯優於INNODB。壓縮後的索引也能節約一些磁盤空間。MYISAM擁有全文索引的功能,這可以極大地優化LIKE查詢的效率。

如果你的應用程序一定要使用事務,毫無疑問你要選擇INNODB引擎

如果是用MyISAM的話,merge引擎可以大大加快應用部門的開發速度,他們只要對這個merge表做一些select count(*)操作,非常適合大項目總量約幾億的rows某一類型(如日誌,調查統計)的業務表。

14.sql執行慢的原因有哪些,如何進行sql優化?

一、導致SQL執行慢的原因

1、硬件問題。如網絡速度慢,內存不足,I/O吞吐量小,磁盤空間滿了等。

2、沒有索引或者索引失效。(一般在互聯網公司,DBA會在半夜把表鎖了,重新建立一遍索引,因爲當你刪除某個數據的時候,索引的樹結構就不完整了。所以互聯網公司的數據做的是假刪除,一是爲了做數據分析,二是爲了不破壞索引 )

3、數據過多(分庫分表)

4、服務器調優及各個參數設置(調整my.cnf)

二、分析原因時,一定要找切入點

1、先觀察,開啓慢查詢日誌,設置相應的閾值(比如超過3秒就是慢SQL),在生產環境跑上個一天過後,看看哪些SQL比較慢。

2、Explain和慢SQL分析。比如SQL語句寫的爛,索引沒有或失效,關聯查詢太多(有時候是設計缺陷或者不得以的需求)等等。

3、Show Profile是比Explain更近一步的執行細節,可以查詢到執行每一個SQL都幹了什麼事,這些事分別花了多少秒。

4、找DBA或者運維對MySQL進行服務器的參數調優。
解析:
(1)explain出來的各種item的意義

id:每個被獨立執行的操作的標誌,表示對象被操作的順序。一般來說, id 值大,先被執行;如果 id 值相同,則順序從上到下。
select_type:查詢中每個 select 子句的類型。
table:名字,被操作的對象名稱,通常的表名(或者別名),但是也有其他格式。
partitions:匹配的分區信息。
type:join 類型。
possible_keys:列出可能會用到的索引。
key:實際用到的索引。
key_len:用到的索引鍵的平均長度,單位爲字節。
ref:表示本行被操作的對象的參照對象,可能是一個常量用 const 表示,也可能是其他表的
key 指向的對象,比如說驅動表的連接列。
rows:估計每次需要掃描的行數。
filtered:rows*filtered/100 表示該步驟最後得到的行數(估計值)。
extra:重要的補充信息。

(2)profile的意義以及使用場景

Profile 用來分析 sql 性能的消耗分佈情況。當用 explain 無法解決慢 SQL 的時候,需要用profile 來對 sql 進行更細緻的分析,找出 sql 所花的時間大部分消耗在哪個部分,確認 sql的性能瓶頸。

(3)explain 中的索引問題

Explain 結果中,一般來說,要看到儘量用 index(type 爲 const、 ref 等, key 列有值),避免使用全表掃描(type 顯式爲 ALL)。比如說有 where 條件且選擇性不錯的列,需要建立索引。
被驅動表的連接列,也需要建立索引。被驅動表的連接列也可能會跟 where 條件列一起建立聯合索引。當有排序或者 group by 的需求時,也可以考慮建立索引來達到直接排序和彙總的需求。

參考:高性能Mysql——創建高性能的索引

15.視圖的作用,視圖可以更改麼?

視圖是虛擬的表,與包含數據的表不一樣,視圖只包含使用時動態檢索數據的查詢;不包含任何列或數據。使用視圖可以簡化複雜的sql操作,隱藏具體的細節,保護數據;視圖創建後,可以使用與表相同的方式利用它們。
視圖不能被索引,也不能有關聯的觸發器或默認值,如果視圖本身內有order by 則對視圖再次order by將被覆蓋。
創建視圖:create view XXX as XXXXXXXXXXXXXX;
對於某些視圖比如未使用聯結子查詢分組聚集函數Distinct Union等,是可以對其更新的,對視圖的更新將對基表進行更新;但是視圖主要用於簡化檢索,保護數據,並不用於更新,而且大部分視圖都不可以更新。

16. 說一說MySQL中的鎖機制

按粒度分:

  • 表級鎖:粒度最大的一種鎖,表示對當前操作的整張表加鎖。開銷小,加鎖快;不會出現死鎖;鎖定粒度大,發生鎖衝突的概率最高,併發度最低
  • 行級鎖:粒度最小的一種鎖,表示只針對當前操作的行進行加鎖。開銷大,加鎖慢;會出現死鎖;鎖定粒度最小,發生鎖衝突的概率最低,併發度最高
  • 頁級鎖:粒度介於行級鎖和表級鎖中間的一種鎖。開銷、加鎖時間和併發度界於表鎖和行鎖之間;會出現死鎖

按操作分:

  • 讀鎖(共享鎖):針對同一份數據,多個讀取操作可以同時進行,不互相影響
  • 寫鎖(排它鎖):當前寫操作沒有完成前,會阻斷其他寫鎖和讀鎖

行級死鎖
在這裏插入圖片描述

17. 數據庫事務四大特性?

原子性(Atomic):一個事務中的所有操作,要麼全部完成,要麼全部不完成,不會結束在中間某個環節。事務在執行過程中發生錯誤,會被回滾到事務開始前的狀態,就像這個事務從來沒有執行過一樣
一致性(Consistency):在事務開始之前和事務結束以後, 數據庫的完整性沒有被破壞
隔離性(Isolation):數據庫允許多個併發事務同時對其數據進行讀寫和修改的能力,隔離性可以防止多個事務併發執行時由於交叉執行而導致數據的不一致。事務隔離分爲不同級別,包括讀未提交(Read uncommitted)、讀提交(read committed)、可重複讀(repeatable read)和串行化(Serializable)
持久性(Durability):事務處理結束後,對數據的修改就是永久的,即便系統故障也不會丟失

18.ACID、BASE和CAP?

參考:DDBS BASE

參考:DDBS CAP

19.MySQL如何獲取當前日期?

SELECT CURRENT_DATE();

20.Mysql驅動程序是什麼?

驅動程序主要幫助編程語言與 MySQL 服務端進行通信,如果連接、關閉、傳輸指令與數據等

21.Innodb引擎有什麼特性?

  • 插入緩衝(insert buffer)
  • 二次寫(double write)
  • 自適應哈希索引(ahi)
  • 預讀(read ahead)

  1. 插入緩衝(insert buffer)解釋:

對於聚簇索引,當執行插入操作時,id列會自動增長,頁中行記錄按id順序存放不需要隨機讀取其它頁的數據。因此,在這樣的情況下,插入操作效率很高。

對於非聚簇索引,可能葉子節點的插入不再有序,這時就需要離散訪問非聚集索引頁,插入性能變低。

Innodb是怎麼解決這個性能變低的情況呢?也就是採用插入緩衝。
對於非聚集類索引的插入和更新操作,不是每一次都直接插入到索引頁中,而是先插入到內存中。具體做法是:如果該索引頁在緩衝池中,直接插入;否則,先將其放入插入緩衝區中,再以一定的頻率和索引頁合併,這時,就可以將同一個索引頁中的多個插入合併到一個IO操作中,大大提高寫性能。

插入緩衝的啓用需要滿足一下兩個條件:
1)索引是非聚簇索引
2)索引不適合唯一的 。
如果輔助索引是唯一的,就不能使用該技術,原因很簡單,因爲如果這樣做,整個索引數據被切分爲2部分,無法保證唯一性。


  1. 二次寫(double write)的解釋:

想象這麼一個場景,當數據庫正在從內存向磁盤寫一個數據頁時,數據庫宕機,從而導致這個頁只寫了部分數據,這就是部分寫失效,它會導致數據丟失。這時是無法通過redo log恢復的,因爲重做日誌記錄的是對頁的物理修改,如果頁本身已經損壞,重做日誌也無能爲力。

從上面分析我們知道,在部分寫失效的情況下,我們在應用重做日誌之前,需要原始頁的一個副本,兩次寫就是爲了解決這個問題。
其原理是這樣的:
1)當刷新緩衝池髒頁時,並不直接寫到數據文件中,而是先拷貝至內存中的兩次寫緩衝區。
2)接着從兩次寫緩衝區分兩次寫入磁盤共享表空間中,每次寫入1MB
3)待第2步完成後,再將兩次寫緩衝區寫入數據文件

下面是它的原理圖。
在這裏插入圖片描述
這樣就可以解決上文提到的部分寫失效的問題,因爲在磁盤共享表空間中已有數據頁副本拷貝,如果數據庫在頁寫入數據文件的過程中宕機,在實例恢復時,可以從共享表空間中找到該頁副本,將其拷貝覆蓋原有的數據頁,再應用重做日誌即可。


  1. 自適應哈希索引(ahi)

哈希索引是一種非常快的等值查找方法(注意:必須是等值,哈希索引對非等值查找方法無能爲力),它查找的時間複雜度爲常量,InnoDB採用自適用哈希索引技術,它會實時監控表上索引的使用情況,如果認爲建立哈希索引可以提高查詢效率,則自動在內存中的“自適應哈希索引緩衝區”建立哈希索引。

之所以該技術稱爲“自適應”是因爲完全由InnoDB自己決定,不需要DBA人爲干預。它是通過緩衝池中的B+樹構造而來,且不需要對整個表建立哈希索引,因此它的數據非常快。


  1. 預讀

參考:https://www.cnblogs.com/geaozhang/p/7397699.html

22.索引對性能有哪些影響?

優點:
減少數據庫服務器需要掃描的數據量
幫助數據庫服務器避免排序和臨時表
將隨機 I/O 變順序I/O
提高查詢速度
唯一索引,能保證數據的唯一性

缺點:
索引的創建和維護耗時隨着數據量的增加而增加
對錶中數據進行增刪改時,索引也要動態維護,降低了數據的維護速度
增大磁盤佔用

23.二進制日誌(binlog)的作用?與redo log的區別?

用於複製,在主從複製中,從庫利用主庫上的binlog進行重播,實現主從同步。
用於數據庫的基於時間點的還原。

區別:

  • redo log是在InnoDB存儲引擎層產生,而binlog是MySQL數據庫的上層產生的,並且二進制日誌不僅僅針對INNODB存儲引擎,MySQL數據庫中的任何存儲引擎對於數據庫的更改都會產生二進制日誌。
  • 兩種日誌記錄的內容形式不同。MySQL的binlog是邏輯日誌,其記錄是對應的DDL和DML語句。而innodb存儲引擎層面的重做日誌是物理日誌。
  • 兩種日誌與記錄寫入磁盤的時間點不同,二進制日誌只在事務提交完成後進行一次寫入。而innodb存儲引擎的重做日誌在事務進行中不斷地被寫入,並日志不是隨事務提交的順序進行寫入的。
  • binlog可以作爲恢復數據使用,主從複製搭建,redo log作爲異常宕機或者介質故障後的數據恢復使用。
  • binlog不是循環使用,在寫滿或者重啓之後,會生成新的binlog文件,redo log是循環使用。

24.InnoDB的行鎖/表鎖?

mysql的行鎖是通過索引加載的,即是行鎖是加在索引響應的行上的

要是對應的SQL語句沒有走索引,則會全表掃描,此時取而代之的是表鎖

表鎖:不會出現死鎖,發生鎖衝突機率高,併發低。(表鎖總是一次性獲得所需的全部鎖,要麼全部滿足,要麼全部等待。所以不會產生死鎖。)
行鎖:會出現死鎖,發生鎖衝突機率低,併發高。

行鎖分 共享鎖 和 排它鎖。
共享鎖又稱:讀鎖。當一個事務對某幾行上讀鎖時,允許其他事務對這幾行進行讀操作,但不允許其進行寫操作,也不允許其他事務給這幾行上排它鎖,但允許上讀鎖。
select math from zje where math>60 lock in share mode;
排它鎖又稱:寫鎖。當一個事務對某幾個上寫鎖時,不允許其他事務寫,但允許讀。更不允許其他事務給這幾行上任何鎖。包括寫鎖。
select math from zje where math >60 for update;

25.什麼是MVCC ?

MVCC全稱是: Multiversion concurrency control,多版本併發控制,它看起來就像是樂觀鎖的實現,做到了讀的非阻塞。

參考:MVCC

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章