日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

数据库常考面试知识点

發(fā)布時間:2024/2/28 数据库 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据库常考面试知识点 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1)什么是存儲過程?有哪些優(yōu)缺點(diǎn)?

存儲過程就像是編程語言中的函數(shù)一樣,封裝了我們的代碼(PLSQL,T-SQL)

例如:

-------------創(chuàng)建名為GetUserAccount的存儲過程---------------- create?Procedure?GetUserAccount as select?*?from?UserAccount go-------------執(zhí)行上面的存儲過程---------------- exec?GetUserAccount

存儲過程的優(yōu)點(diǎn):

  • 能夠?qū)⒋a封裝起來

  • 保存在數(shù)據(jù)庫之中

  • 讓編程語言進(jìn)行調(diào)用

  • 存儲過程是一個預(yù)編譯的代碼塊,執(zhí)行效率比較高

  • 一個存儲過程替代大量T_SQL語句 ,可以降低網(wǎng)絡(luò)通信量,提高通信速率

存儲過程的缺點(diǎn):

  • 每個數(shù)據(jù)庫的存儲過程語法幾乎都不一樣,十分難以維護(hù)(不通用)

  • 業(yè)務(wù)邏輯放在數(shù)據(jù)庫上,難以迭代


2)三大范式

  • 思考這樣的一個例子:

我們現(xiàn)在需要建立一個描述學(xué)校教務(wù)的數(shù)據(jù)庫,該數(shù)據(jù)庫涉及的對象包括學(xué)生的學(xué)號(Sno)、所在系(Sdept)、系主任姓名(Mname)、課程號(Cno)和成績(Grade),假設(shè)我們使用單一的關(guān)系模式 Student 來表示,那么根據(jù)現(xiàn)實(shí)世界已知的信息,會描述成以下這個樣子:

?

?

但是,這個關(guān)系模式存在以下問題:

(1) 數(shù)據(jù)冗余
比如,每一個系的系主任姓名重復(fù)出現(xiàn),重復(fù)次數(shù)與該系所有學(xué)生的所有課程成績出現(xiàn)次數(shù)相同,這將浪費(fèi)大量的存儲空間。
(2)更新異常(update anomalies)
由于數(shù)據(jù)冗余,當(dāng)更新數(shù)據(jù)庫中的數(shù)據(jù)時,系統(tǒng)要付出很大的代價來維護(hù)數(shù)據(jù)庫的完整性,否則會面臨數(shù)據(jù)不一致的危險。比如,某系更換系主任后,必須修改與該系學(xué)生有關(guān)的每一個元組。
(3)插入異常(insertion anomalies)
如果一個系剛成立,尚無學(xué)生,則無法把這個系及其系主任的信息存入數(shù)據(jù)庫。
(4)刪除異常(deletion anomalies)
如果某個系的學(xué)生全部畢業(yè)了,則在刪除該系學(xué)生信息的同時,這個系及其系主任的信息也丟失了。

  • 總結(jié):?所以,我們在設(shè)計數(shù)據(jù)庫的時候,就需要滿足一定的規(guī)范要求,而滿足不同程度要求的就是不同的范式。

  • 第一范式:?列不可分

1NF(第一范式)是對屬性具有原子性的要求,不可再分,例如:

?

如果認(rèn)為最后一列還可以再分成出生年,出生月,出生日,則它就不滿足第一范式的要求。

  • 第二范式:?消除非主屬性對碼的部分函數(shù)依賴

2NF(第二范式)是對記錄有唯一性的要求,即實(shí)體的唯一性,不存在部分依賴,每一列與主鍵都相關(guān),例如:

?

該表明顯說明了兩個事物:學(xué)生信息和課程信息;正常的依賴應(yīng)該是:學(xué)分依賴課程號,姓名依賴學(xué)號,但這里存在非主鍵字段對碼的部分依賴,即與主鍵不相關(guān),不滿足第二范式的要求。

可能存在的問題:

  • 數(shù)據(jù)冗余:每條記錄都含有相同信息;

  • 刪除異常:刪除所有學(xué)生成績,就把課程信息全刪除了;

  • 插入異常:學(xué)生未選課,無法記錄進(jìn)數(shù)據(jù)庫;

  • 更新異常:調(diào)整課程學(xué)分,所有行都調(diào)整。

正確的做法:

?

  • 第三范式:?消除非主屬性對碼的傳遞函數(shù)依賴

3NF(第三范式)對字段有冗余性的要求,任何字段不能由其他字段派生出來,它要求字段沒有冗余,即不存在依賴傳遞,例如:

?

?

很明顯,學(xué)院電話是一個冗余字段,因?yàn)榇嬖谝蕾噦鬟f:(學(xué)號)→(學(xué)生)→(學(xué)院)→(學(xué)院電話)

可能會存在的問題:

  • 數(shù)據(jù)冗余:有重復(fù)值;

  • 更新異常:有重復(fù)的冗余信息,修改時需要同時修改多條記錄,否則會出現(xiàn)數(shù)據(jù)不一致的情況 。

正確的做法:

?


3)數(shù)據(jù)庫索引

  • 什么是索引?

索引是對數(shù)據(jù)庫表中一個或多個列的值進(jìn)行排序的數(shù)據(jù)結(jié)構(gòu),以協(xié)助快速查詢、更新數(shù)據(jù)庫表中數(shù)據(jù)。

你也可以這樣理解:索引就是加快檢索表中數(shù)據(jù)的方法。數(shù)據(jù)庫的索引類似于書籍的索引。在書籍中,索引允許用戶不必翻閱完整個書就能迅速地找到所需要的信息。在數(shù)據(jù)庫中,索引也允許數(shù)據(jù)庫程序迅速地找到表中的數(shù)據(jù),而不必掃描整個數(shù)據(jù)庫。

  • 底層數(shù)據(jù)結(jié)構(gòu)是什么,為什么使用這種數(shù)據(jù)結(jié)構(gòu)?

(1)底層數(shù)據(jù)結(jié)構(gòu)是B+樹:
在數(shù)據(jù)結(jié)構(gòu)中,我們最為常見的搜索結(jié)構(gòu)就是二叉搜索樹和AVL樹(高度平衡的二叉搜索樹,為了提高二叉搜索樹的效率,減少樹的平均搜索長度)了。然而,無論二叉搜索樹還是AVL樹,當(dāng)數(shù)據(jù)量比較大時,都會由于樹的深度過大而造成I/O讀寫過于頻繁,進(jìn)而導(dǎo)致查詢效率低下,因此對于索引而言,多叉樹結(jié)構(gòu)成為不二選擇。特別地,B-Tree的各種操作能使B樹保持較低的高度,從而保證高效的查找效率。

(2)使用B+樹的原因:
查找速度快、效率高,在查找的過程中,每次都能拋棄掉一部分節(jié)點(diǎn),減少遍歷個數(shù)。(此時,你應(yīng)該在白紙上畫出什么是B+樹)

  • 索引的分類?

  • 唯一索引:唯一索引不允許兩行具有相同的索引值

  • 主鍵索引:為表定義一個主鍵將自動創(chuàng)建主鍵索引,主鍵索引是唯一索引的特殊類型。主鍵索引要求主鍵中的每個值是唯一的,并且不能為空

  • 聚集索引(Clustered):表中各行的物理順序與鍵值的邏輯(索引)順序相同,每個表只能有一個

  • 非聚集索引(Non-clustered):非聚集索引指定表的邏輯順序。數(shù)據(jù)存儲在一個位置,索引存儲在另一個位置,索引中包含指向數(shù)據(jù)存儲位置的指針。可以有多個,小于249個

  • 索引的優(yōu)缺點(diǎn)?

(1)優(yōu)點(diǎn):

  • 大大加快數(shù)據(jù)的檢索速度,這也是創(chuàng)建索引的最主要的原因;

  • 加速表和表之間的連接;

  • 在使用分組和排序子句進(jìn)行數(shù)據(jù)檢索時,同樣可以顯著減少查詢中分組和排序的時間;

  • 通過創(chuàng)建唯一性索引,可以保證數(shù)據(jù)庫表中每一行數(shù)據(jù)的唯一性;

(2)缺點(diǎn):

  • 時間方面:創(chuàng)建索引和維護(hù)索引要耗費(fèi)時間,具體地,當(dāng)對表中的數(shù)據(jù)進(jìn)行增加、刪除和修改的時候,索引也要動態(tài)的維護(hù),這樣就降低了數(shù)據(jù)的維護(hù)速度;

  • 空間方面:索引需要占物理空間。

  • 什么樣的字段適合創(chuàng)建索引?

  • 經(jīng)常作查詢選擇的字段

  • 經(jīng)常作表連接的字段

  • 經(jīng)常出現(xiàn)在order by, group by, distinct 后面的字段

  • 創(chuàng)建索引時需要注意什么?

  • 非空字段:應(yīng)該指定列為NOT NULL,除非你想存儲NULL。在mysql中,含有空值的列很難進(jìn)行查詢優(yōu)化,因?yàn)樗鼈兪沟盟饕?、索引的統(tǒng)計信息以及比較運(yùn)算更加復(fù)雜。你應(yīng)該用0、一個特殊的值或者一個空串代替空值;

  • 取值離散大的字段:(變量各個取值之間的差異程度)的列放到聯(lián)合索引的前面,可以通過count()函數(shù)查看字段的差異值,返回值越大說明字段的唯一值越多字段的離散程度高;

  • 索引字段越小越好:數(shù)據(jù)庫的數(shù)據(jù)存儲以頁為單位一頁存儲的數(shù)據(jù)越多一次IO操作獲取的數(shù)據(jù)越大效率越高。


4)聽說過事務(wù)嗎?(必考)

事務(wù)簡單來說:一個 Session 中所進(jìn)行所有的操作,要么同時成功,要么同時失敗;作為單個邏輯工作單元執(zhí)行的一系列操作,滿足四大特性:

  • 原子性(Atomicity):事務(wù)作為一個整體被執(zhí)行 ,要么全部執(zhí)行,要么全部不執(zhí)行

  • 一致性(Consistency):保證數(shù)據(jù)庫狀態(tài)從一個一致狀態(tài)轉(zhuǎn)變?yōu)榱硪粋€一致狀態(tài)

  • 隔離性(Isolation):多個事務(wù)并發(fā)執(zhí)行時,一個事務(wù)的執(zhí)行不應(yīng)影響其他事務(wù)的執(zhí)行

  • 持久性(Durability):一個事務(wù)一旦提交,對數(shù)據(jù)庫的修改應(yīng)該永久保存

    • 實(shí)例說明:

    /**?我們來模擬A向B賬號轉(zhuǎn)賬的場景*???A和B賬戶都有1000塊,現(xiàn)在我讓A賬戶向B賬號轉(zhuǎn)500塊錢***/ //JDBC默認(rèn)的情況下是關(guān)閉事務(wù)的,下面我們看看關(guān)閉事務(wù)去操作轉(zhuǎn)賬操作有什么問題//A賬戶減去500塊 String?sql?=?"UPDATE?a?SET?money=money-500?"; preparedStatement?=?connection.prepareStatement(sql); preparedStatement.executeUpdate();//B賬戶多了500塊 String?sql2?=?"UPDATE?b?SET?money=money+500"; preparedStatement?=?connection.prepareStatement(sql2); preparedStatement.executeUpdate();

    從上面看,我們的確可以發(fā)現(xiàn)A向B轉(zhuǎn)賬,成功了??墒侨绻鸄向B轉(zhuǎn)賬的過程中出現(xiàn)了問題呢?下面模擬一下

    //?A賬戶減去500塊 String?sql?=?"UPDATE?a?SET?money=money-500?"; preparedStatement?=?connection.prepareStatement(sql); preparedStatement.executeUpdate();//?這里模擬出現(xiàn)問題 int?a?=?3?/?0;String?sql2?=?"UPDATE?b?SET?money=money+500"; preparedStatement?=?connection.prepareStatement(sql2); preparedStatement.executeUpdate();

    顯然,上面代碼是會拋出異常的,我們再來查詢一下數(shù)據(jù)。A賬戶少了500塊錢,B賬戶的錢沒有增加。這明顯是不合理的。

    我們可以通過事務(wù)來解決上面出現(xiàn)的問題:

    ????//?開啟事務(wù),對數(shù)據(jù)的操作就不會立即生效。connection.setAutoCommit(false);//?A賬戶減去500塊String?sql?=?"UPDATE?a?SET?money=money-500?";preparedStatement?=?connection.prepareStatement(sql);preparedStatement.executeUpdate();//?在轉(zhuǎn)賬過程中出現(xiàn)問題int?a?=?3?/?0;//?B賬戶多500塊String?sql2?=?"UPDATE?b?SET?money=money+500";preparedStatement?=?connection.prepareStatement(sql2);preparedStatement.executeUpdate();//?如果程序能執(zhí)行到這里,沒有拋出異常,我們就提交數(shù)據(jù)connection.commit();//?關(guān)閉事務(wù)【自動提交】connection.setAutoCommit(true);}?catch(SQLException?e)?{try?{//?如果出現(xiàn)了異常,就會進(jìn)到這里來,我們就把事務(wù)回滾【將數(shù)據(jù)變成原來那樣】connection.rollback();//?關(guān)閉事務(wù)【自動提交】connection.setAutoCommit(true);}?catch?(SQLException?e1)?{e1.printStackTrace();} }

    上面的程序也一樣拋出了異常,A賬戶錢沒有減少,B賬戶的錢也沒有增加。

    • 注意:當(dāng)Connection遇到一個未處理的SQLException時,系統(tǒng)會非正常退出,事務(wù)也會自動回滾,但如果程序捕獲到了異常,是需要在catch中顯式回滾事務(wù)的。


    5)事務(wù)的并發(fā)問題有哪幾種?

  • 丟失更新:一個事務(wù)的更新覆蓋了另一個事務(wù)的更新;

  • 臟讀:一個事務(wù)讀取了另一個事務(wù)未提交的數(shù)據(jù);

  • 不可重復(fù)讀:不可重復(fù)讀的重點(diǎn)是修改,同樣條件下兩次讀取結(jié)果不同,也就是說,被讀取的數(shù)據(jù)可以被其它事務(wù)修改;

  • 幻讀:幻讀的重點(diǎn)在于新增或者刪除,同樣條件下兩次讀出來的記錄數(shù)不一樣。


  • 6)事務(wù)的隔離級別有哪幾種?

    隔離級別決定了一個session中的事務(wù)可能對另一個session中的事務(wù)的影響。ANSI標(biāo)準(zhǔn)定義了4個隔離級別,MySQL的InnoDB都支持,分別是:

  • 讀未提交(READ UNCOMMITTED):最低級別的隔離,通常又稱為dirty read,它允許一個事務(wù)讀取另一個事務(wù)還沒 commit 的數(shù)據(jù),這樣可能會提高性能,但是會導(dǎo)致臟讀問題;

  • 讀已提交(READ COMMITTED):在一個事務(wù)中只允許對其它事務(wù)已經(jīng) commit 的記錄可見,該隔離級別不能避免不可重復(fù)讀問題;

  • 可重復(fù)讀(REPEATABLE READ):在一個事務(wù)開始后,其他事務(wù)對數(shù)據(jù)庫的修改在本事務(wù)中不可見,直到本事務(wù) commit 或 rollback。但是,其他事務(wù)的 insert/delete 操作對該事務(wù)是可見的,也就是說,該隔離級別并不能避免幻讀問題。在一個事務(wù)中重復(fù) select 的結(jié)果一樣,除非本事務(wù)中 update 數(shù)據(jù)庫。

  • 序列化(SERIALIZABLE):最高級別的隔離,只允許事務(wù)串行執(zhí)行。

  • MySQL默認(rèn)的隔離級別是可重復(fù)讀(REPEATABLE READ)

    • MySql 的事務(wù)支持

    MySQL的事務(wù)支持不是綁定在MySQL服務(wù)器本身,而是與存儲引擎相關(guān):

    • MyISAM:不支持事務(wù),用于只讀程序提高性能;

    • InnoDB:支持ACID事務(wù)、行級鎖、并發(fā);

    • Berkeley DB:支持事務(wù)。


    7)什么是視圖?以及視圖的使用場景有哪些?

    視圖是一種虛擬的表,具有和物理表相同的功能??梢詫σ晥D進(jìn)行增,改,查,操作,試圖通常是有一個表或者多個表的行或列的子集。對視圖的修改不影響基本表。它使得我們獲取數(shù)據(jù)更容易,相比多表查詢。

    如下兩種場景一般會使用到視圖:

  • 不希望訪問者獲取整個表的信息,只暴露部分字段給訪問者,所以就建一個虛表,就是視圖。

  • 查詢的數(shù)據(jù)來源于不同的表,而查詢者希望以統(tǒng)一的方式查詢,這樣也可以建立一個視圖,把多個表查詢結(jié)果聯(lián)合起來,查詢者只需要直接從視圖中獲取數(shù)據(jù),不必考慮數(shù)據(jù)來源于不同表所帶來的差異。

  • 注意:這個視圖是在數(shù)據(jù)庫中創(chuàng)建的 而不是用代碼創(chuàng)建的。


    8)drop,delete與truncate的區(qū)別?

    drop 直接刪除表;truncate 刪除表中數(shù)據(jù),再插入時自增長id又從1開始 ;delete 刪除表中數(shù)據(jù),可以加where字句。

    • drop table:

    • 屬于DDL(Data Definition Language,數(shù)據(jù)庫定義語言)

    • 不可回滾

    • 不可帶 where

    • 表內(nèi)容和結(jié)構(gòu)刪除

    • 刪除速度快

    • truncate table:

    • 屬于DDL(Data Definition Language,數(shù)據(jù)庫定義語言)

    • 不可回滾

    • 不可帶 where

    • 表內(nèi)容刪除

    • 刪除速度快

    • delete from:

    • 屬于DML

    • 可回滾

    • 可帶where

    • 表結(jié)構(gòu)在,表內(nèi)容要看where執(zhí)行的情況

    • 刪除速度慢,需要逐行刪除

    • 使用簡要說明:

    • 不再需要一張表的時候,用drop

    • 想刪除部分?jǐn)?shù)據(jù)行時候,用delete,并且?guī)蟱here子句

    • 保留表而刪除所有數(shù)據(jù)的時候用truncate


    9)觸發(fā)器的作用?

    觸發(fā)器是與表相關(guān)的數(shù)據(jù)庫對象,在滿足定義條件時觸發(fā),并執(zhí)行觸發(fā)器中定義的語句集合。觸發(fā)器的這種特性可以協(xié)助應(yīng)用在數(shù)據(jù)庫端確保數(shù)據(jù)庫的完整性。


    10)數(shù)據(jù)庫的樂觀鎖和悲觀鎖是什么?

    數(shù)據(jù)庫管理系統(tǒng)(DBMS)中的并發(fā)控制的任務(wù)是確保在多個事務(wù)同時存取數(shù)據(jù)庫中同一數(shù)據(jù)時不破壞事務(wù)的隔離性和統(tǒng)一性以及數(shù)據(jù)庫的統(tǒng)一性。

    樂觀并發(fā)控制(樂觀鎖)和悲觀并發(fā)控制(悲觀鎖)是并發(fā)控制主要采用的技術(shù)手段。

    • 悲觀鎖:假定會發(fā)生并發(fā)沖突,屏蔽一切可能違反數(shù)據(jù)完整性的操作

    悲觀鎖是一種利用數(shù)據(jù)庫內(nèi)部機(jī)制提供的鎖的方式,也就是對更新的數(shù)據(jù)加鎖,這樣在并發(fā)期間一旦有一個事務(wù)持有了數(shù)據(jù)庫記錄的鎖,其他的線程將不能再對數(shù)據(jù)進(jìn)行更新了,這就是悲觀鎖的實(shí)現(xiàn)方式。

    MySQL InnoDB中使用悲觀鎖:

    要使用悲觀鎖,我們必須關(guān)閉mysql數(shù)據(jù)庫的自動提交屬性,因?yàn)镸ySQL默認(rèn)使用autocommit模式,也就是說,當(dāng)你執(zhí)行一個更新操作后,MySQL會立刻將結(jié)果進(jìn)行提交。set autocommit=0;

    //0.開始事務(wù) begin;/begin?work;/start?transaction;?(三者選一就可以) //1.查詢出商品信息 select?status?from?t_goods?where?id=1?for?update; //2.根據(jù)商品信息生成訂單 insert?into?t_orders?(id,goods_id)?values?(null,1); //3.修改商品status為2 update?t_goods?set?status=2; //4.提交事務(wù) commit;/commit?work;

    上面的查詢語句中,我們使用了?select…for update?的方式,這樣就通過開啟排他鎖的方式實(shí)現(xiàn)了悲觀鎖。此時在t_goods表中,id為1的 那條數(shù)據(jù)就被我們鎖定了,其它的事務(wù)必須等本次事務(wù)提交之后才能執(zhí)行。這樣我們可以保證當(dāng)前的數(shù)據(jù)不會被其它事務(wù)修改。

    上面我們提到,使用?select…for update?會把數(shù)據(jù)給鎖住,不過我們需要注意一些鎖的級別,MySQL InnoDB默認(rèn)行級鎖。行級鎖都是基于索引的,如果一條SQL語句用不到索引是不會使用行級鎖的,會使用表級鎖把整張表鎖住,這點(diǎn)需要注意。

    優(yōu)點(diǎn)與不足:

    悲觀并發(fā)控制實(shí)際上是“先取鎖再訪問”的保守策略,為數(shù)據(jù)處理的安全提供了保證。但是在效率方面,處理加鎖的機(jī)制會讓數(shù)據(jù)庫產(chǎn)生額外的開銷,還有增加產(chǎn)生死鎖的機(jī)會;另外,在只讀型事務(wù)處理中由于不會產(chǎn)生沖突,也沒必要使用鎖,這樣做只能增加系統(tǒng)負(fù)載;還有會降低了并行性,一個事務(wù)如果鎖定了某行數(shù)據(jù),其他事務(wù)就必須等待該事務(wù)處理完才可以處理那行數(shù)

    • 樂觀鎖:假設(shè)不會發(fā)生并發(fā)沖突,只在提交操作時檢查是否違反數(shù)據(jù)完整性。

    樂觀鎖是一種不會阻塞其他線程并發(fā)的控制,它不會使用數(shù)據(jù)庫的鎖進(jìn)行實(shí)現(xiàn),它的設(shè)計里面由于不阻塞其他線程,所以并不會引起線程頻繁掛起和恢復(fù),這樣便能夠提高并發(fā)能力,所以也有人把它稱為非阻塞鎖。一般的實(shí)現(xiàn)樂觀鎖的方式就是記錄數(shù)據(jù)版本。

    數(shù)據(jù)版本,為數(shù)據(jù)增加的一個版本標(biāo)識。當(dāng)讀取數(shù)據(jù)時,將版本標(biāo)識的值一同讀出,數(shù)據(jù)每更新一次,同時對版本標(biāo)識進(jìn)行更新。當(dāng)我們提交更新的時候,判斷數(shù)據(jù)庫表對應(yīng)記錄的當(dāng)前版本信息與第一次取出來的版本標(biāo)識進(jìn)行比對,如果數(shù)據(jù)庫表當(dāng)前版本號與第一次取出來的版本標(biāo)識值相等,則予以更新,否則認(rèn)為是過期數(shù)據(jù)。

    實(shí)現(xiàn)數(shù)據(jù)版本有兩種方式,第一種是使用版本號,第二種是使用時間戳。

    使用版本號實(shí)現(xiàn)樂觀鎖:

    使用版本號時,可以在數(shù)據(jù)初始化時指定一個版本號,每次對數(shù)據(jù)的更新操作都對版本號執(zhí)行+1操作。并判斷當(dāng)前版本號是不是該數(shù)據(jù)的最新的版本號。

    1.查詢出商品信息 select?(status,status,version)?from?t_goods?where?id=#{id} 2.根據(jù)商品信息生成訂單 3.修改商品status為2 update?t_goods? set?status=2,version=version+1 where?id=#{id}?and?version=#{version};

    優(yōu)點(diǎn)與不足:

    樂觀并發(fā)控制相信事務(wù)之間的數(shù)據(jù)競爭(data race)的概率是比較小的,因此盡可能直接做下去,直到提交的時候才去鎖定,所以不會產(chǎn)生任何鎖和死鎖。但如果直接簡單這么做,還是有可能會遇到不可預(yù)期的結(jié)果,例如兩個事務(wù)都讀取了數(shù)據(jù)庫的某一行,經(jīng)過修改以后寫回數(shù)據(jù)庫,這時就遇到了問題。

    參考文章:深入理解樂觀鎖與悲觀鎖


    11)超鍵、候選鍵、主鍵、外鍵分別是什么?

    • 超鍵:在關(guān)系中能唯一標(biāo)識元組的屬性集稱為關(guān)系模式的超鍵。一個屬性可以為作為一個超鍵,多個屬性組合在一起也可以作為一個超鍵。超鍵包含候選鍵和主鍵。

    • 候選鍵(候選碼):是最小超鍵,即沒有冗余元素的超鍵。

    • 主鍵(主碼):數(shù)據(jù)庫表中對儲存數(shù)據(jù)對象予以唯一和完整標(biāo)識的數(shù)據(jù)列或?qū)傩缘慕M合。一個數(shù)據(jù)列只能有一個主鍵,且主鍵的取值不能缺失,即不能為空值(Null)。

    • 外鍵:在一個表中存在的另一個表的主鍵稱此表的外鍵。

    候選碼和主碼:

    例子:郵寄地址(城市名,街道名,郵政編碼,單位名,收件人)

    • 它有兩個候選鍵:{城市名,街道名} 和 {街道名,郵政編碼}

    • 如果我選取{城市名,街道名}作為唯一標(biāo)識實(shí)體的屬性,那么{城市名,街道名} 就是主碼(主鍵)


    12)SQL 約束有哪幾種?

    • NOT NULL: 用于控制字段的內(nèi)容一定不能為空(NULL)。

    • UNIQUE: 控件字段內(nèi)容不能重復(fù),一個表允許有多個 Unique 約束。

    • PRIMARY KEY: 也是用于控件字段內(nèi)容不能重復(fù),但它在一個表只允許出現(xiàn)一個。

    • FOREIGN KEY: 用于預(yù)防破壞表之間連接的動作,也能防止非法數(shù)據(jù)插入外鍵列,因?yàn)樗仨毷撬赶虻哪莻€表中的值之一。

    • CHECK: 用于控制字段的值范圍。


    13)MySQL存儲引擎中的MyISAM和InnoDB區(qū)別詳解

    在MySQL 5.5之前,MyISAM是mysql的默認(rèn)數(shù)據(jù)庫引擎,其由早期的ISAM(Indexed Sequential Access Method:有索引的順序訪問方法)所改良。雖然MyISAM性能極佳,但卻有一個顯著的缺點(diǎn):不支持事務(wù)處理。不過,MySQL也導(dǎo)入了另一種數(shù)據(jù)庫引擎InnoDB,以強(qiáng)化參考完整性與并發(fā)違規(guī)處理機(jī)制,后來就逐漸取代MyISAM。

    InnoDB是MySQL的數(shù)據(jù)庫引擎之一,其由Innobase oy公司所開發(fā),2006年五月由甲骨文公司并購。與傳統(tǒng)的ISAM、MyISAM相比,InnoDB的最大特色就是支持ACID兼容的事務(wù)功能,類似于PostgreSQL。目前InnoDB采用雙軌制授權(quán),一是GPL授權(quán),另一是專有軟件授權(quán)。具體地,MyISAM與InnoDB作為MySQL的兩大存儲引擎的差異主要包括:

    • 存儲結(jié)構(gòu):每個MyISAM在磁盤上存儲成三個文件:第一個文件的名字以表的名字開始,擴(kuò)展名指出文件類型。.frm文件存儲表定義,數(shù)據(jù)文件的擴(kuò)展名為.MYD (MYData),索引文件的擴(kuò)展名是.MYI (MYIndex)。InnoDB所有的表都保存在同一個數(shù)據(jù)文件中(也可能是多個文件,或者是獨(dú)立的表空間文件),InnoDB表的大小只受限于操作系統(tǒng)文件的大小,一般為2GB。

    • 存儲空間:MyISAM可被壓縮,占據(jù)的存儲空間較小,支持靜態(tài)表、動態(tài)表、壓縮表三種不同的存儲格式。InnoDB需要更多的內(nèi)存和存儲,它會在主內(nèi)存中建立其專用的緩沖池用于高速緩沖數(shù)據(jù)和索引。

    • 可移植性、備份及恢復(fù):MyISAM的數(shù)據(jù)是以文件的形式存儲,所以在跨平臺的數(shù)據(jù)轉(zhuǎn)移中會很方便,同時在備份和恢復(fù)時也可單獨(dú)針對某個表進(jìn)行操作。InnoDB免費(fèi)的方案可以是拷貝數(shù)據(jù)文件、備份 binlog,或者用 mysqldump,在數(shù)據(jù)量達(dá)到幾十G的時候就相對痛苦了。

    • 事務(wù)支持:MyISAM強(qiáng)調(diào)的是性能,每次查詢具有原子性,其執(zhí)行數(shù)度比InnoDB類型更快,但是不提供事務(wù)支持。InnoDB提供事務(wù)、外鍵等高級數(shù)據(jù)庫功能,具有事務(wù)提交、回滾和崩潰修復(fù)能力。

    • AUTO_INCREMENT:在MyISAM中,可以和其他字段一起建立聯(lián)合索引。引擎的自動增長列必須是索引,如果是組合索引,自動增長可以不是第一列,它可以根據(jù)前面幾列進(jìn)行排序后遞增。InnoDB中必須包含只有該字段的索引,并且引擎的自動增長列必須是索引,如果是組合索引也必須是組合索引的第一列。

    • 表鎖差異:MyISAM只支持表級鎖,用戶在操作MyISAM表時,select、update、delete和insert語句都會給表自動加鎖,如果加鎖以后的表滿足insert并發(fā)的情況下,可以在表的尾部插入新的數(shù)據(jù)。InnoDB支持事務(wù)和行級鎖。行鎖大幅度提高了多用戶并發(fā)操作的新能,但是InnoDB的行鎖,只是在WHERE的主鍵是有效的,非主鍵的WHERE都會鎖全表的。

    • 全文索引:MyISAM支持 FULLTEXT類型的全文索引;InnoDB不支持FULLTEXT類型的全文索引,但是innodb可以使用sphinx插件支持全文索引,并且效果更好。

    • 表主鍵:MyISAM允許沒有任何索引和主鍵的表存在,索引都是保存行的地址。對于InnoDB,如果沒有設(shè)定主鍵或者非空唯一索引,就會自動生成一個6字節(jié)的主鍵(用戶不可見),數(shù)據(jù)是主索引的一部分,附加索引保存的是主索引的值。

    • 表的具體行數(shù):MyISAM保存表的總行數(shù),select count() from table;會直接取出出該值;而InnoDB沒有保存表的總行數(shù),如果使用select count() from table;就會遍歷整個表,消耗相當(dāng)大,但是在加了wehre條件后,myisam和innodb處理的方式都一樣。

    • CURD操作:在MyISAM中,如果執(zhí)行大量的SELECT,MyISAM是更好的選擇。對于InnoDB,如果你的數(shù)據(jù)執(zhí)行大量的INSERT或UPDATE,出于性能方面的考慮,應(yīng)該使用InnoDB表。DELETE從性能上InnoDB更優(yōu),但DELETE FROM table時,InnoDB不會重新建立表,而是一行一行的刪除,在innodb上如果要清空保存有大量數(shù)據(jù)的表,最好使用truncate table這個命令。

    • 外鍵:MyISAM不支持外鍵,而InnoDB支持外鍵。

    通過上述的分析,基本上可以考慮使用InnoDB來替代MyISAM引擎了,原因是InnoDB自身很多良好的特點(diǎn),比如事務(wù)支持、存儲過程、視圖、行級鎖、外鍵等等。尤其在并發(fā)很多的情況下,相信InnoDB的表現(xiàn)肯定要比MyISAM強(qiáng)很多。另外,必須需要注意的是,任何一種表都不是萬能的,合適的才是最好的,才能最大的發(fā)揮MySQL的性能優(yōu)勢。如果是不復(fù)雜的、非關(guān)鍵的Web應(yīng)用,還是可以繼續(xù)考慮MyISAM的,這個具體情況具體考慮。


    14)MyIASM和Innodb兩種引擎所使用的索引的數(shù)據(jù)結(jié)構(gòu)是什么?

    答案:都是B+樹!

    MyIASM引擎,B+樹的數(shù)據(jù)結(jié)構(gòu)中存儲的內(nèi)容實(shí)際上是實(shí)際數(shù)據(jù)的地址值。也就是說它的索引和實(shí)際數(shù)據(jù)是分開的,只不過使用索引指向了實(shí)際數(shù)據(jù)。這種索引的模式被稱為非聚集索引。

    Innodb引擎的索引的數(shù)據(jù)結(jié)構(gòu)也是B+樹,只不過數(shù)據(jù)結(jié)構(gòu)中存儲的都是實(shí)際的數(shù)據(jù),這種索引有被稱為聚集索引。


    15)varchar和char的區(qū)別

    char是一種固定長度的類型,varchar是一種可變長度的類型,例如:

    定義一個char[10]和varchar[10],如果存進(jìn)去的是 'test',那么char所占的長度依然為10,除了字符 'test' 外,后面跟六個空格,varchar就立馬把長度變?yōu)?了,取數(shù)據(jù)的時候,char類型的要用trim()去掉多余的空格,而varchar是不需要的

    char的存取速度還是要比varchar要快得多,因?yàn)槠溟L度固定,方便程序的存儲于查找

    char也為此付出的是空間的代價,因?yàn)槠溟L度固定,所以難免會有多余的空格占位符占據(jù)空間,可謂是以空間換取時間效率。

    varchar是以空間效率為首位。

    char的存儲方式是:對英文字符(ASCII)占用1個字節(jié),對一個漢字占用兩個字節(jié)。

    varchar的存儲方式是:對每個英文字符占用2個字節(jié),漢字也占用2個字節(jié)。
    兩者的存儲數(shù)據(jù)都非unicode的字符數(shù)據(jù)。


    16)主鍵、自增主鍵、主鍵索引與唯一索引概念區(qū)別

  • 主鍵:指字段?唯一、不為空值?的列;

  • 主鍵索引:指的就是主鍵,主鍵是索引的一種,是唯一索引的特殊類型。創(chuàng)建主鍵的時候,數(shù)據(jù)庫默認(rèn)會為主鍵創(chuàng)建一個唯一索引;

  • 自增主鍵:字段類型為數(shù)字、自增、并且是主鍵;

  • 唯一索引:索引列的值必須唯一,但允許有空值。主鍵是唯一索引,這樣說沒錯;但反過來說,唯一索引也是主鍵就錯誤了,因?yàn)槲ㄒ凰饕试S空值,主鍵不允許有空值,所以不能說唯一索引也是主鍵。


  • 17)主鍵就是聚集索引嗎?主鍵和索引有什么區(qū)別?

    主鍵是一種特殊的唯一性索引,其可以是聚集索引,也可以是非聚集索引。在SQLServer中,主鍵的創(chuàng)建必須依賴于索引,默認(rèn)創(chuàng)建的是聚集索引,但也可以顯式指定為非聚集索引。InnoDB作為MySQL存儲引擎時,默認(rèn)按照主鍵進(jìn)行聚集,如果沒有定義主鍵,InnoDB會試著使用唯一的非空索引來代替。如果沒有這種索引,InnoDB就會定義隱藏的主鍵然后在上面進(jìn)行聚集。所以,對于聚集索引來說,你創(chuàng)建主鍵的時候,自動就創(chuàng)建了主鍵的聚集索引。


    18)實(shí)踐中如何優(yōu)化MySQL

    實(shí)踐中,MySQL的優(yōu)化主要涉及SQL語句及索引的優(yōu)化、數(shù)據(jù)表結(jié)構(gòu)的優(yōu)化、系統(tǒng)配置的優(yōu)化和硬件的優(yōu)化四個方面,如下圖所示:

    ?

    ⑴ SQL語句優(yōu)化:

    SQL語句的優(yōu)化主要包括三個問題,即如何發(fā)現(xiàn)有問題的SQL、如何分析SQL的執(zhí)行計劃以及如何優(yōu)化SQL,下面將逐一解釋。

    ① 怎么發(fā)現(xiàn)有問題的SQL?(通過MySQL慢查詢?nèi)罩緦τ行蕟栴}的SQL進(jìn)行監(jiān)控)

    MySQL的慢查詢?nèi)罩臼荕ySQL提供的一種日志記錄,它用來記錄在MySQL中響應(yīng)時間超過閥值的語句,具體指運(yùn)行時間超過long_query_time值的SQL,則會被記錄到慢查詢?nèi)罩局?。long_query_time的默認(rèn)值為10,意思是運(yùn)行10s以上的語句。慢查詢?nèi)罩镜南嚓P(guān)參數(shù)如下所示:

    ?

    通過MySQL的慢查詢?nèi)罩?#xff0c;我們可以查詢出執(zhí)行的次數(shù)多占用的時間長的SQL、可以通過pt_query_disgest(一種mysql慢日志分析工具)分析Rows examine(MySQL執(zhí)行器需要檢查的行數(shù))項(xiàng)去找出IO大的SQL以及發(fā)現(xiàn)未命中索引的SQL,對于這些SQL,都是我們優(yōu)化的對象。

    ② 通過explain查詢和分析SQL的執(zhí)行計劃:

    使用 EXPLAIN 關(guān)鍵字可以知道MySQL是如何處理你的SQL語句的,以便分析查詢語句或是表結(jié)構(gòu)的性能瓶頸。通過explain命令可以得到表的讀取順序、數(shù)據(jù)讀取操作的操作類型、哪些索引可以使用、哪些索引被實(shí)際使用、表之間的引用以及每張表有多少行被優(yōu)化器查詢等問題。當(dāng)擴(kuò)展列extra出現(xiàn)Using filesort和Using temporay,則往往表示SQL需要優(yōu)化了。

    ③ SQL語句的優(yōu)化:

    ⒈優(yōu)化insert語句:一次插入多值;

    ⒉應(yīng)盡量避免在 where 子句中使用!=或<>操作符,否則將引擎放棄使用索引而進(jìn)行全表掃描;

    ⒊應(yīng)盡量避免在 where 子句中對字段進(jìn)行null值判斷,否則將導(dǎo)致引擎放棄使用索引而進(jìn)行全表掃描;

    ⒋優(yōu)化嵌套查詢:子查詢可以被更有效率的連接(Join)替代;

    ⒌很多時候用 exists 代替 in 是一個好的選擇。

    ⒍選擇最有效率的表名順序:數(shù)據(jù)庫的解析器按照從右到左的順序處理FROM子句中的表名,FROM子句中寫在最后的表將被最先處理

    在FROM子句中包含多個表的情況下:

    • 如果三個表是完全無關(guān)系的話,將記錄和列名最少的表,寫在最后,然后依次類推

    • 也就是說:選擇記錄條數(shù)最少的表放在最后

    如果有3個以上的表連接查詢:

    • 如果三個表是有關(guān)系的話,將引用最多的表,放在最后,然后依次類推。

    • 也就是說:被其他表所引用的表放在最后

    ⒎用IN代替OR:

    select?*?from?emp?where?sal?=?1500?or?sal?=?3000?or?sal?=?800; select?*?from?emp?where?sal?in?(1500,3000,800);

    ⒏SELECT子句中避免使用*號:

    我們最開始接觸 SQL 的時候,“*” 號是可以獲取表中全部的字段數(shù)據(jù)的,但是它要通過查詢數(shù)據(jù)字典完成,這意味著將消耗更多的時間,而且使用 “*” 號寫出來的 SQL 語句也不夠直觀。


    ⑵ 索引優(yōu)化:

    建議在經(jīng)常作查詢選擇的字段、經(jīng)常作表連接的字段以及經(jīng)常出現(xiàn)在 order by、group by、distinct 后面的字段中建立索引。但必須注意以下幾種可能會引起索引失效的情形:

    • 以 “%(表示任意0個或多個字符)” 開頭的 LIKE 語句,模糊匹配;

    • OR語句前后沒有同時使用索引;

    • 數(shù)據(jù)類型出現(xiàn)隱式轉(zhuǎn)化(如varchar不加單引號的話可能會自動轉(zhuǎn)換為int型);

    • 對于多列索引,必須滿足最左匹配原則(eg,多列索引col1、col2和col3,則 索引生效的情形包括col1或col1,col2或col1,col2,col3)。


    ⑶ 數(shù)據(jù)庫表結(jié)構(gòu)的優(yōu)化:

    ① 選擇合適數(shù)據(jù)類型:

    • 使用較小的數(shù)據(jù)類型解決問題;

    • 使用簡單的數(shù)據(jù)類型(mysql處理int要比varchar容易);

    • 盡可能的使用not null 定義字段;

    • 盡量避免使用text類型,非用不可時最好考慮分表;

    ② 表的范式的優(yōu)化:

    一般情況下,表的設(shè)計應(yīng)該遵循三大范式。

    ③ 表的垂直拆分:

    把含有多個列的表拆分成多個表,解決表寬度問題,具體包括以下幾種拆分手段:

    • 把不常用的字段單獨(dú)放在同一個表中;

    • 把大字段獨(dú)立放入一個表中;

    • 把經(jīng)常使用的字段放在一起;

    這樣做的好處是非常明顯的,具體包括:拆分后業(yè)務(wù)清晰,拆分規(guī)則明確、系統(tǒng)之間整合或擴(kuò)展容易、數(shù)據(jù)維護(hù)簡單

    ④ 表的水平拆分:

    表的水平拆分用于解決數(shù)據(jù)表中數(shù)據(jù)過大的問題,水平拆分每一個表的結(jié)構(gòu)都是完全一致的。一般地,將數(shù)據(jù)平分到N張表中的常用方法包括以下兩種:

    • 對ID進(jìn)行hash運(yùn)算,如果要拆分成5個表,mod(id,5)取出0~4個值;

    • 針對不同的hashID將數(shù)據(jù)存入不同的表中;

    表的水平拆分會帶來一些問題和挑戰(zhàn),包括跨分區(qū)表的數(shù)據(jù)查詢、統(tǒng)計及后臺報表的操作等問題,但也帶來了一些切實(shí)的好處:

    • 表分割后可以降低在查詢時需要讀的數(shù)據(jù)和索引的頁數(shù),同時也降低了索引的層數(shù),提高查詢速度;

    • 表中的數(shù)據(jù)本來就有獨(dú)立性,例如表中分別記錄各個地區(qū)的數(shù)據(jù)或不同時期的數(shù)據(jù),特別是有些數(shù)據(jù)常用,而另外一些數(shù)據(jù)不常用。

    • 需要把數(shù)據(jù)存放到多個數(shù)據(jù)庫中,提高系統(tǒng)的總體可用性(分庫,雞蛋不能放在同一個籃子里)。


    ⑷ 系統(tǒng)配置的優(yōu)化:

    • 操作系統(tǒng)配置的優(yōu)化:增加TCP支持的隊列數(shù)

    • mysql配置文件優(yōu)化:Innodb緩存池設(shè)置(innodb_buffer_pool_size,推薦總內(nèi)存的75%)和緩存池的個數(shù)(innodb_buffer_pool_instances)


    ⑸ 硬件的優(yōu)化:

    • CPU:核心數(shù)多并且主頻高的

    • 內(nèi)存:增大內(nèi)存

    • 磁盤配置和選擇:磁盤性能

    總結(jié)

    以上是生活随笔為你收集整理的数据库常考面试知识点的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。