数据库知识点梳理
數(shù)據(jù)庫面試常考題
文章目錄
- 數(shù)據(jù)庫面試常考題
- **一、 left join, right join, inner join區(qū)別?**
- **二、 存儲(chǔ)引擎MyIsam和Innodb區(qū)別?**
- **三、 mysql的優(yōu)化手段有哪些?**
- **四、 如何查看Mysql執(zhí)行計(jì)劃?**
- **五、 索引是什么? 有什么用? 如何建立? 索引的底層實(shí)現(xiàn)是什么? 什么情況下適合建立索引, 什么情況下不適合建立索引?**
- **六、 什么是存儲(chǔ)過程?有什么好處?**
- **七、 樂觀鎖和悲觀鎖是什么?**
- **八、 表鎖、頁鎖、行鎖的區(qū)別?**
- **九、 having和where的區(qū)別?**
- **十一、 事務(wù)的特點(diǎn)有哪些?**
- **十二、 觸發(fā)器是什么?**
- **十三、 為什么大部分?jǐn)?shù)據(jù)庫索引的實(shí)現(xiàn)使用B+樹而不是哈希表或紅黑樹之類的?**
一、 left join, right join, inner join區(qū)別?
- left join(左聯(lián)接) 返回包括左表中的所有記錄和右表中聯(lián)結(jié)字段相等的記錄
- right join(右聯(lián)接) 返回包括右表中的所有記錄和左表中聯(lián)結(jié)字段相等的記錄
- inner join(等值連接) 只返回兩個(gè)表中聯(lián)結(jié)字段相等的行
注意:在某些數(shù)據(jù)庫中l(wèi)eft join等同于left outer join
舉個(gè)例子:
表A記錄如下
| 1 | a20050111 |
| 2 | a20050112 |
| 3 | a20050113 |
| 4 | a20050114 |
| 5 | a20050115 |
表B記錄如下 |bID| bName | |:--|:--| | 1 | 2006032401 | | 2 | 2006032402 | | 3 | 2006032403 | | 4 | 2006032404 | | 8 | 2006032408 |
1、sql語句如下: select * from A left join B on A.aID = B.bID
結(jié)果如下: |aID| aNum |bID| bName | |:--|:--|:--|:--| | 1 | a20050111 | 1 | 2006032401 | | 2 | a20050112 | 2 | 2006032402 | | 3 | a20050113 | 3 | 2006032403 | | 4 | a20050114 | 4 | 2006032404 | | 5 | a20050115 | NULL| NULL |
(所影響的行數(shù)為5行) **結(jié)果說明:** left join是以A表的記錄為基礎(chǔ)的,A可以看成左表,B可以看成右表,left join是以左表為準(zhǔn)的。換句話說,左表(A)的記錄將會(huì)全部表示出來,而右表(B)只會(huì)顯示符合搜索條件的記錄(例子中為:A.aID = B.bID)。B表記錄不足的地方均為NULL。
2、sql語句如下: select * from A right join B on A.aID =B.bID
結(jié)果如下: |aID| aNum |bID| bName | |:--|:--|:--|:--| | 1 | a20050111 | 1 | 2006032401 | | 2 | a20050112 | 2 | 2006032402 | | 3 | a20050113 | 3 | 2006032403 | | 4 | a20050114 | 4 | 2006032404 | | NULL | NULL | 8| 2006032408 |
(所影響的行數(shù)為5行) **結(jié)果說明**: 仔細(xì)觀察一下,就會(huì)發(fā)現(xiàn),和left join的結(jié)果剛好相反,這次是以右表(B)為基礎(chǔ)的,A表不足的地方用NULL填充。
3、sql語句如下: ``` select * from A inner join B on A.aID = B.bID ```
結(jié)果如下: | aID | aNum | bID | bName | |:--|:--|:--|:--| | 1 | a20050111 | 1 | 2006032401 | | 2 | a20050112 | 2 | 2006032402 | | 3 | a20050113 | 3 | 2006032403 | | 4 | a20050114 | 4 | 2006032404 |
結(jié)果說明: 很明顯,這里只顯示出了A.aID = B.bID的記錄,這說明inner join并不以誰為基礎(chǔ),它只顯示符合條件的記錄。
二、 存儲(chǔ)引擎MyIsam和Innodb區(qū)別?
(1)MyIsam類型不支持事務(wù)處理等高級(jí)處理,而Innodb類型支持
事務(wù)處理是指原子性操作。例如,支持事務(wù)處理的Innodb表中,你發(fā)了一個(gè)帖子執(zhí)行insert語句,來插入帖子內(nèi)容,插入后要執(zhí)行一個(gè)update語句來增加你的積分。假設(shè)一種特殊情況突然發(fā)生,insert成功了,update操作卻沒有被執(zhí)行。也就是說你發(fā)了帖子卻沒有增加相應(yīng)的積分。這就會(huì)造成用戶不滿。如果使用了事務(wù)處理,insert和update都放入到事務(wù)中去執(zhí)行,這個(gè)時(shí)候,只有當(dāng)insert和update兩條語句都執(zhí)行生成的時(shí)候才會(huì)將數(shù)據(jù)更新、寫入到表中。如果其中任何一條語句失敗,那么就會(huì)回滾為初始狀態(tài),不執(zhí)行寫入。這樣就保證了insert和update肯定是一同執(zhí)行的。
(2)MyIsam表不支持外鍵。innodb支持外鍵
(3)在執(zhí)行數(shù)據(jù)寫入的操作(insert,update,delete)的時(shí)候,MyIsam表會(huì)鎖表,而innodb表會(huì)鎖行。
通俗的講,就是你執(zhí)行一個(gè)update語句,那么MyIsam表會(huì)將整個(gè)表都鎖住,其他的insert和delete、update都會(huì)被拒之門外,等到這個(gè)update語句執(zhí)行完成后才會(huì)被依次執(zhí)行。而鎖行,就是說,你執(zhí)行update語句時(shí),只會(huì)將這一條記錄進(jìn)行鎖定,只有針對(duì)這條記錄的其他寫入、更新操作會(huì)被阻塞并等待這條update語句執(zhí)行完畢后再執(zhí)行,針對(duì)其他記錄的寫入操作不會(huì)有影響。但是innodb表的行鎖也不是絕對(duì)的,如果在執(zhí)行一個(gè)sql語句時(shí),mysql不能確定要掃描的范圍,innodb表同樣會(huì)鎖全表,例如update table set num =1 where name like “%aaa%”
(4)表的具體行數(shù)
select count(*) from table , MyIsam只要簡單的讀出保存好的行數(shù),注意的是,當(dāng)count(*)語句包含where條件時(shí),兩種表的操作是一樣的。
innodb中不保存表的具體行數(shù),也就是說,執(zhí)行select count(*) from table時(shí),innodb要掃描一遍整個(gè)表來計(jì)算有多少行。
總結(jié):
因此,當(dāng)你的數(shù)據(jù)庫有大量的寫入、更新操作而查詢比較少或者數(shù)據(jù)完整性要求比較高的時(shí)候就選擇innodb表。當(dāng)你的數(shù)據(jù)庫主要以查詢?yōu)橹?#xff0c;相比較而言更新和寫入比較少,并且業(yè)務(wù)方面數(shù)據(jù)完整性要求不那么嚴(yán)格,就選擇myisam表。因?yàn)镸yIsam表的查詢操作效率和速度都比innodb要快。
InnoDB的設(shè)計(jì)目標(biāo)是處理大容量數(shù)據(jù)庫系統(tǒng),它的CPU利用率是其它基于磁盤的關(guān)系數(shù)據(jù)庫引擎所不能比的。
我覺得使用InnoDB可以應(yīng)對(duì)更為復(fù)雜的情況,特別是對(duì)并發(fā)的處理要比MyISAM高效。同時(shí)結(jié)合memcache也可以緩存SELECT來減少SELECT查詢,從而提高整體性能。
使用以下mysql sql語句,可以給表設(shè)定數(shù)據(jù)庫引擎:
ALTER TABLE `wp_posts` ENGINE = MyISAM;查看當(dāng)前數(shù)據(jù)庫的引擎,可看出默認(rèn)是InnoDB類型。

三、 mysql的優(yōu)化手段有哪些?
MYSQL數(shù)據(jù)庫優(yōu)化的八種方式:
(1)選取最適用的字段屬性
MYSQL可以很好的支持大數(shù)據(jù)量的存取,但是一般來說,數(shù)據(jù)庫中的表越小,在它上面執(zhí)行的查詢也就會(huì)越快。因此,在創(chuàng)建表的時(shí)候,為了獲得更好的性能,我們可以將表中字段的寬度設(shè)得盡可能小。
例如,在定義郵政編碼這個(gè)字段時(shí),如果將其設(shè)置為CHAR(255),顯然給數(shù)據(jù)庫增加了不必要的空間,甚至使用VARCHAR這種類型也是多余的,因?yàn)镃HAR(6)就可以很好的完成任務(wù)了。同樣的,如果可以的話,我們應(yīng)該使用MEDIUMINT而不是BIGINT來定義整型字段。
另外一個(gè)提高效率的方法是在可能的情況下,應(yīng)該盡量把字段設(shè)置為NOT NULL,這樣在將來執(zhí)行查詢的時(shí)候,數(shù)據(jù)庫不用去比較NULL值。
對(duì)于某些文本字段,例如“省份”或者“性別”,我們可以將它們定義為ENUM類型。因?yàn)樵贛YSQL中,ENUM類型被當(dāng)做數(shù)值型數(shù)據(jù)來處理,而數(shù)值型數(shù)據(jù)被處理起來的速度要比文本類型快得多。這樣,我們又可以提高數(shù)據(jù)庫的性能。
(2)使用連接(JOIN)來代替子查詢(Sub-Queries)
例如:我們要將客戶基本信息表中沒有任何訂單的客戶刪除掉,就可以利用子查詢先從銷售信息表中將所有發(fā)出訂單的客戶ID取出來,然后將結(jié)果傳遞給主查詢,如下所示:
如果使用連接(JOIN)來完成這個(gè)查詢工作,速度將會(huì)快很多。尤其是當(dāng)salesinfo表中對(duì)CustomerID建有索引的話,性能將會(huì)更好。查詢?nèi)缦?#xff1a;
SELECT * FROM customerinfo
LEFT JOIN salesinfo ON customerinfo.customerid = salesinfo.customerif
Where salesinfo.customerid is NULL
連接(JOIN)之所以更有效率一些,是因?yàn)镸YSQL不需要在內(nèi)存中創(chuàng)建臨時(shí)表來完成這個(gè)邏輯上的需要兩個(gè)步驟的查詢工作。
(3)使用聯(lián)合(UNION)來代替手動(dòng)創(chuàng)建的臨時(shí)表
UNION查詢可以把需要使用臨時(shí)表的兩條或更多的select查詢合并在一個(gè)查詢中。在客戶端的查詢會(huì)話結(jié)束的時(shí)候,臨時(shí)表會(huì)被自動(dòng)刪除,從而保證數(shù)據(jù)庫整齊、高效。使用union來創(chuàng)建查詢的時(shí)候,我們只需要用union作為關(guān)鍵字把多個(gè)select語句連接起來就可以了,要注意的是所有select語句中的字段數(shù)目要相同。
例子:
(4)事務(wù)
盡管我們可以使用子查詢、連接(join)和聯(lián)合(union)來創(chuàng)建各種各樣的查詢,但不是所有的數(shù)據(jù)庫操作都可以只用一條或少數(shù)幾條sql語句就可以完成的。更多的時(shí)候是需要用到一系列的語句來完成某種工作。但是如果這個(gè)語句塊中的某一條語句運(yùn)行出錯(cuò)的時(shí)候,整個(gè)語句塊的操作就會(huì)變得不確定起來。因此要盡量使用事務(wù),它的作用:要么語句塊中每條語句都操作成功,要么都失敗。換句話說,就是可以保持?jǐn)?shù)據(jù)庫中數(shù)據(jù)的一致性和完整性。事務(wù)以BEGIN關(guān)鍵字開始,COMMIT關(guān)鍵字結(jié)束。在這之間的一條SQL操作失敗,那么,rollback命令就可以把數(shù)據(jù)庫恢復(fù)到BEGIN開始之前的狀態(tài)。
例子:
事務(wù)的另一個(gè)重要作用是當(dāng)多個(gè)用戶同時(shí)使用相同的數(shù)據(jù)源時(shí),它可以利用鎖定數(shù)據(jù)庫的方法來為用戶提供一種安全的訪問方式,這樣可以保證用戶的操作不被其他的用戶所干擾。
(5)鎖定表
通過鎖定表來防止其他的訪問對(duì)我們正在操作的表進(jìn)行插入、更新或者刪除的操作。
例子:
這里,我們用一個(gè)select語句取出初始數(shù)據(jù),通過一些計(jì)算,用update語句將新值更新到表中。包含有WRITE關(guān)鍵字的LOCKTABLE語句可以保證在UNLOCKTABLES命令被執(zhí)行之前,不會(huì)有其他的訪問來對(duì)inventory進(jìn)行插入、更新或者刪除的操作。
(6)使用外鍵
鎖定表的方法可以維護(hù)數(shù)據(jù)的完整性,但是它卻不能保證數(shù)據(jù)的關(guān)聯(lián)性。這個(gè)時(shí)候我們就可以使用外鍵。
(7)使用索引
索引是提高數(shù)據(jù)庫性能的常用方法,它可以令數(shù)據(jù)庫服務(wù)器以比沒有索引快得多的速度檢索特定的行,尤其是在查詢語句當(dāng)中包含有MAX(),MIN()和ORDERBY這些命令的時(shí)候,性能提高更為明顯。
對(duì)哪些字段建立索引?
索引應(yīng)建立在那些將用于JOIN,WHERE判斷和ORDERBY排序的字段上。
全文索引在MYSQL中是一個(gè)FULLTEXT類型索引,但僅能用于MYISAM類型的表。對(duì)于一個(gè)大的數(shù)據(jù)庫,將數(shù)據(jù)裝載到一個(gè)沒有FULLTEXT索引的表中,然后再使用ALTERTABLE或CREATEINDEX創(chuàng)建索引,將是非常快的。但如果將數(shù)據(jù)裝載到一個(gè)已經(jīng)有FULLTEXT索引的表中,執(zhí)行過程將會(huì)非常慢。
(8)優(yōu)化查詢語句
1、最好在相同類型的字段間進(jìn)行比較的操作
2、在建有索引的字段上盡量不要使用函數(shù)進(jìn)行操作。
例如,在一個(gè)DATE類型的字段上使用YEAR()函數(shù)時(shí),將會(huì)使索引不能發(fā)揮應(yīng)有的作用。所以下面的兩個(gè)查詢雖然返回的結(jié)果一樣,但后者要比前者快的多。
3、在搜索字符型字段時(shí),我們有時(shí)會(huì)使用LIKE關(guān)鍵字和通配符,這種做法雖然簡單,但卻也是以犧牲系統(tǒng)性能為代價(jià)的。
例如下面的查詢將會(huì)比較表中的每一條記錄
但是如果換用下面的查詢,返回的結(jié)果一樣,但速度就要快上很多
SELECT * FROM books WEHRE name>=“MYSQL” and name < “MYSQM”最后,應(yīng)該注意避免在查詢中讓MYSQL進(jìn)行自動(dòng)類型轉(zhuǎn)換,因?yàn)檗D(zhuǎn)換過程也會(huì)使索引變得不起作用。
四、 如何查看Mysql執(zhí)行計(jì)劃?
mysql的查看執(zhí)行計(jì)劃的語句:explain+你要執(zhí)行的sql語句
例如:
id是一組數(shù)字,表示查詢中執(zhí)行select子句或操作表的順序。id如果相同,則可以認(rèn)為是一組,從上往下順序執(zhí)行,所有組中,id越高,優(yōu)先級(jí)越高,越容易執(zhí)行。
select_type有simple,primary,subquery,derived(衍生),union,unionresult.
simple表示查詢中不包含子查詢或者union。
當(dāng)查詢中包含任何復(fù)雜的子部分,最外層的查詢被標(biāo)記成primary。在select或where列表中包含了子查詢,則子查詢被標(biāo)記成subquery。在from的列表中包含的子查詢被標(biāo)記成derived。…省略
參考網(wǎng)址:
http://www.cnblogs.com/ggjucheng/archive/2012/11/11/2765237.html
mysql執(zhí)行計(jì)劃的局限
五、 索引是什么? 有什么用? 如何建立? 索引的底層實(shí)現(xiàn)是什么? 什么情況下適合建立索引, 什么情況下不適合建立索引?
(1)什么索引?
數(shù)據(jù)庫索引,是幫助數(shù)據(jù)庫系統(tǒng)高效獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu),以協(xié)助快速查詢、更新數(shù)據(jù)庫表中數(shù)據(jù)。
(2)建立索引的目的?
在數(shù)據(jù)庫系統(tǒng)中建立索引主要有以下作用:
(3)缺點(diǎn)
1. 索引需要占物理內(nèi)存
2. 當(dāng)對(duì)表中的數(shù)據(jù)進(jìn)行增加、刪除和修改的時(shí)候,索引也要?jiǎng)討B(tài)的維護(hù),降低了數(shù)據(jù)的維護(hù)速度
(4)mysql是使用B+樹實(shí)現(xiàn)其索引結(jié)構(gòu)
(5)創(chuàng)建索引的辦法:
例如使用create index語句或者使用創(chuàng)建索引向?qū)?/li>
例如在表中定義主鍵約束或者唯一性鍵約束時(shí),同時(shí)也創(chuàng)建了索引。
當(dāng)在表中定義主鍵或者唯一性鍵約束時(shí),如果表中已經(jīng)有了使用create index語句創(chuàng)建的標(biāo)準(zhǔn)索引時(shí),那么主鍵約束或者唯一性鍵約束創(chuàng)建的索引覆蓋以前創(chuàng)建的標(biāo)準(zhǔn)索引。也就是說,主鍵約束或者唯一性鍵約束創(chuàng)建的索引的優(yōu)先級(jí)高于使用create index語句創(chuàng)建的索引。
(6)幾種索引類型的比較
聚集索引:物理存儲(chǔ)按照索引排序(表中行的物理順序與鍵值的索引順序相同),葉子結(jié)點(diǎn)即存儲(chǔ)了真實(shí)的數(shù)據(jù)行。
非聚集索引:物理存儲(chǔ)位置不按照索引排序,葉子結(jié)點(diǎn)包含索引字段值及指向數(shù)據(jù)頁數(shù)據(jù)行的邏輯指針。
一張表中只能創(chuàng)建一個(gè)聚集索引,但表中的每一列都可以有自己的非聚集索引。
唯一性索引:這一列數(shù)據(jù)不重復(fù),只能一個(gè)為NULL
主鍵索引:主鍵索引是唯一索引的特定類型。不重復(fù),不允許為空。主鍵只能有一個(gè)。
普通索引:create index等建立的索引,alter tablename add index …
(7) 外鍵約束的要求:
六、 什么是存儲(chǔ)過程?有什么好處?
(1)什么是存儲(chǔ)過程?
存儲(chǔ)過程是一個(gè)被定義并保存在數(shù)據(jù)庫服務(wù)器中的sql語句集,是一種介于應(yīng)用程序和數(shù)據(jù)庫間的編程接口,也是封裝重復(fù)性工作的一種有效方法,它支持用戶變量、條件執(zhí)行及其它的編程功能。
(2)存儲(chǔ)過程的語法
CREATE PROCEDURE procedure_name([paramters[,...]])[attributes] BEGINbody_statement END;注:
procedure_name:存儲(chǔ)過程的名字
paramters:存儲(chǔ)過程的過程參數(shù),包含:IN、OUT及INOUT。IN代表輸入或傳入值,在存儲(chǔ)過程中被修改,但不返回;OUT代表輸出或傳出值,在存儲(chǔ)過程中被修改,并返回;INOUT代表輸入輸出,在存儲(chǔ)過程中被修改,并返回;body_statement:存儲(chǔ)過程體,這里可以放入sql集,也可以內(nèi)嵌存儲(chǔ)過程。
好處:
相對(duì)于直接使用sql語句,在應(yīng)用程序中直接調(diào)用存儲(chǔ)過程有以下好處:
(1)減少網(wǎng)絡(luò)通信量。調(diào)用一個(gè)行數(shù)不多的存儲(chǔ)過程與直接調(diào)用sql語句的網(wǎng)絡(luò)通信量可能不會(huì)有很大的差別,可是如果存儲(chǔ)過程包含上百行sql語句,那么其性能絕對(duì)比一條一條的調(diào)用sql語句要高的多。
(2)執(zhí)行速度更快。有兩個(gè)原因:首先,在存儲(chǔ)過程創(chuàng)建的時(shí)候,數(shù)據(jù)庫已經(jīng)對(duì)其進(jìn)行了一次解析和優(yōu)化。其次,存儲(chǔ)過程一旦執(zhí)行,在內(nèi)存中就會(huì)保留一份這個(gè)存儲(chǔ)過程,這樣下次再執(zhí)行同樣的存儲(chǔ)過程時(shí),可以從內(nèi)存中直接調(diào)用。
(3)更強(qiáng)的適應(yīng)性:由于存儲(chǔ)過程對(duì)數(shù)據(jù)庫的訪問時(shí)通過存儲(chǔ)過程來進(jìn)行的,因此數(shù)據(jù)庫開發(fā)人員可以在不改動(dòng)存儲(chǔ)過程接口的情況下對(duì)數(shù)據(jù)庫進(jìn)行任何改動(dòng),而這些改動(dòng)不會(huì)對(duì)應(yīng)用程序造成影響。
(4)布式工作:應(yīng)用程序和數(shù)據(jù)庫的編碼工作可以分別獨(dú)立進(jìn)行,而不會(huì)相互壓制。
七、 樂觀鎖和悲觀鎖是什么?
樂觀鎖和悲觀鎖是兩種并發(fā)控制機(jī)制。
首先了解一下為什么需要鎖(并發(fā)控制)?
在多用戶環(huán)境中,在同一時(shí)間可能會(huì)有多個(gè)用戶更新相同的記錄,這會(huì)產(chǎn)生沖突。這就是著名的并發(fā)性問題。
典型的沖突有:
(1)丟失更新:一個(gè)事務(wù)的更新覆蓋了其他事務(wù)的更新結(jié)果,這就是所謂的更新丟失。例如:用戶A把值從6改為2,用戶B把值從2改為6,則用戶A丟失了他的更新。
(2)臟讀:又稱無效數(shù)據(jù)的讀出,是指在數(shù)據(jù)庫訪問中,事務(wù)T1將某一值修改,然后事務(wù)T2讀取該值,此后T1因?yàn)槟撤N原因撤銷對(duì)該值的修改,這就導(dǎo)致了T2所讀取到到的數(shù)據(jù)是無效的。臟讀就是指當(dāng)一個(gè)事務(wù)正在訪問數(shù)據(jù),并且對(duì)數(shù)據(jù)進(jìn)行了修改,而這種修改還沒有提交到數(shù)據(jù)庫中,這時(shí),另外一個(gè)事務(wù)也訪問這個(gè)數(shù)據(jù),然后使用了這個(gè)數(shù)據(jù)。
并發(fā)控制機(jī)制:
最常用的處理多用戶并發(fā)訪問的方法是加鎖。當(dāng)一個(gè)用戶鎖住數(shù)據(jù)庫中的某個(gè)對(duì)象時(shí),其他用戶就不能再訪問該對(duì)象。加鎖對(duì)并發(fā)訪問的影響體現(xiàn)在鎖的粒度上。比如,放在一個(gè)表上的鎖限制對(duì)整個(gè)表的并發(fā)訪問;放在數(shù)據(jù)頁上的鎖限制了對(duì)整個(gè)數(shù)據(jù)頁的訪問;放在行上的鎖只限制對(duì)該行的并發(fā)訪問。可見行鎖粒度最小,并發(fā)訪問最好,頁鎖粒度最大,表鎖介于兩者之間。
悲觀鎖:假定會(huì)發(fā)生并發(fā)沖突,屏蔽一切可能違反數(shù)據(jù)完整性的操作。
悲觀鎖假定其他用戶企圖訪問或者改變你正在訪問、更改的對(duì)象的概率是很高的,因此在悲觀鎖的環(huán)境中,在你開始改變此對(duì)象之前就將該對(duì)象鎖住,并且直到你提交了所作的更改之后才釋放鎖。悲觀的缺陷是不論是頁鎖還是行鎖,加鎖的時(shí)間可能會(huì)很長,這樣可能會(huì)長時(shí)間的限制其他用戶的訪問,也就是說悲觀鎖的并發(fā)訪問性不好。
樂觀鎖:假設(shè)不會(huì)發(fā)生并發(fā)沖突,只在提交操作時(shí)檢查是否違反數(shù)據(jù)完整性。
樂觀鎖不能解決臟讀的問題。樂觀鎖則認(rèn)為其他用戶企圖改變你正在更改的對(duì)象的概率是很小的,因此樂觀鎖直到你準(zhǔn)備提交所作的更改時(shí)才將對(duì)象鎖住,當(dāng)你讀取以及改變?cè)搶?duì)象時(shí)并不加鎖。可見樂觀鎖加鎖的時(shí)間要比悲觀鎖短,樂觀鎖可以用較大的鎖粒度獲得較好的并發(fā)訪問性能。但是如果第二個(gè)用戶恰好在第一個(gè)用戶提交更改之前讀取了該對(duì)象,那么當(dāng)他完成了自己的更改進(jìn)行提交時(shí),數(shù)據(jù)庫就會(huì)發(fā)現(xiàn)該對(duì)象已經(jīng)變化了,這樣,第二個(gè)用戶不得不重新讀取該對(duì)象并作出更改。這說明在樂觀鎖環(huán)境中,會(huì)增加并發(fā)用戶讀取對(duì)象的次數(shù)。
樂觀鎖的應(yīng)用:
(1)使用自增長的整數(shù)表示數(shù)據(jù)版本號(hào)。更新時(shí)檢查版本號(hào)是否一致,比如數(shù)據(jù)庫中數(shù)據(jù)版本為6,更新提交時(shí)version=6+1,使用該version值(=7)與數(shù)據(jù)庫version+1(=7)作比較,如果相等,則可以更新,如果不等則有可能其他程序已更新該記錄,所以返回錯(cuò)誤。
(2)使用時(shí)間戳來實(shí)現(xiàn)。
悲觀鎖應(yīng)用:
需要使用數(shù)據(jù)庫的鎖機(jī)制,比如SQL server的TABLOCKX(排它表鎖)此選項(xiàng)被選中時(shí),SQL server將在整個(gè)表上置排它鎖直至該命令或事務(wù)結(jié)束。這將防止其他進(jìn)程讀取或修改表中的數(shù)據(jù)。
總結(jié):
在實(shí)際生產(chǎn)環(huán)境里邊,如果并發(fā)量不大且不允許臟讀,可以使用悲觀鎖解決并發(fā)問題;但如果系統(tǒng)的并發(fā)非常大的話,悲觀鎖定會(huì)帶來非常大的性能問題,所以我們就要選擇樂觀鎖定的方法。
八、 表鎖、頁鎖、行鎖的區(qū)別?
行級(jí)鎖是mysql中鎖定粒度最細(xì)的一種鎖,表示只針對(duì)當(dāng)前操作的行進(jìn)行加鎖。行級(jí)鎖能大大減少數(shù)據(jù)庫操作的沖突。其加鎖粒度最小,但加鎖的開銷也最大。行級(jí)鎖分為共享鎖和排他鎖。
特點(diǎn):開銷大,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。
表級(jí)鎖是mysql中鎖定粒度最大的一種鎖,表示對(duì)當(dāng)前操作的整張表加鎖,它實(shí)現(xiàn)簡單,資源消耗較少,被大部分Mysql引擎支持。最常使用的myisam和innodb都支持表級(jí)鎖定。表級(jí)鎖定分為表共享讀鎖(共享鎖)和表獨(dú)占寫鎖(排他鎖)。
特點(diǎn):開銷小,加鎖快;不會(huì)出現(xiàn)死鎖;鎖定粒度大,發(fā)出鎖沖突的概率最高,并發(fā)度最低。
頁級(jí)鎖是mysql鐘鎖定粒度介于行級(jí)鎖和表級(jí)鎖中間的一種鎖。表級(jí)鎖速度快,但沖突多,行級(jí)沖突少,但速度慢。所以取了折中的頁級(jí),一次鎖定相鄰的一組記錄。BDB支持頁級(jí)表。
特點(diǎn):開銷和加鎖時(shí)間介于表鎖和行鎖之間;會(huì)出現(xiàn)死鎖;鎖定粒度介于表鎖和行鎖之間,并發(fā)度一般。
上述三種鎖的特性可大致歸納如下:
1) 表級(jí)鎖:開銷小,加鎖快;不會(huì)出現(xiàn)死鎖;鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)度最低。
2) 行級(jí)鎖:開銷大,加鎖慢;會(huì)出現(xiàn)死鎖;鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。
3) 頁面鎖:開銷和加鎖時(shí)間界于表鎖和行鎖之間;會(huì)出現(xiàn)死鎖;鎖定粒度界于表鎖和行鎖之間,并發(fā)度一般。
九、 having和where的區(qū)別?
where語句在group by語句之前,sql會(huì)在分組之前計(jì)算where語句。
having語句在group by語句之后,sql會(huì)在分組之后計(jì)算having語句。
where是一個(gè)約束聲明,使用where約束來自數(shù)據(jù)庫的數(shù)據(jù),where是在結(jié)果返回之前起作用的,where中不能使用聚合函數(shù)。having是一個(gè)過濾聲明,是在查詢返回結(jié)果集以后對(duì)查詢結(jié)果進(jìn)行的過濾操作,在having中可以使用聚合函數(shù)。
在查詢過程中聚合語句(sum,min,max,avg,count)要比having子句優(yōu)先執(zhí)行。而where子句在查詢過程中執(zhí)行優(yōu)先級(jí)高于聚合語句。
例一:要查找平均工資大于3000的部門,則sql語句應(yīng)為:
select department, avg(salary) as average from salary_info group by department having average>3000此時(shí)只能使用having,而不能使用where。一來,我們要使用聚合語句avg;二來,我們要對(duì)聚合后的結(jié)果進(jìn)行篩選(average>3000),因此使用where會(huì)被告知sql有誤。
例二:要查詢每個(gè)部門工資大于3000的員工個(gè)數(shù)
select department, count(*) as c from salary_info where salary>3000 group by department.此處的where不可用having進(jìn)行替換,因?yàn)槭侵苯訉?duì)庫中的數(shù)據(jù)進(jìn)行篩選,而非對(duì)結(jié)果集進(jìn)行篩選。
where和having的執(zhí)行級(jí)別不同
在查詢過程中聚合語句(sum,min,max,avg,count)要比having子句優(yōu)先執(zhí)行.而where子句在查詢過程中執(zhí)行優(yōu)先級(jí)別優(yōu)先于聚合語句(sum,min,max,avg,count)。
having就是來彌補(bǔ)where在分組數(shù)據(jù)判斷時(shí)的不足。因?yàn)閣here執(zhí)行優(yōu)先級(jí)別要快于聚合語句。
##十、 事務(wù)的隔離級(jí)別?
| 未提交讀 | 可能 | 可能 | 可能 |
| 已提交讀 | 不可能 | 可能 | 可能 |
| 可重復(fù)讀 | 不可能 | 不可能 | 可能 |
| 可串行化 | 不可能 | 不可能 | 不可能 |
**未提交讀**:允許臟讀,也就是可能讀取到其他會(huì)話中未提交事務(wù)修改的數(shù)據(jù)。 **已提交讀**:只能讀取到已經(jīng)提交的數(shù)據(jù)。Oracle等多數(shù)數(shù)據(jù)庫默認(rèn)是該級(jí)別(不重復(fù)讀)。 **可重復(fù)讀**:在同一個(gè)事務(wù)內(nèi)的查詢都是事務(wù)開始時(shí)刻一致的,innodb默認(rèn)級(jí)別。在sql標(biāo)準(zhǔn)中,該隔離級(jí)別消除了不可重復(fù)讀,但是還存在幻象讀。 **串行讀**:完全串行化的讀,每次讀都需要獲得表級(jí)共享鎖,讀寫相互都會(huì)阻塞。
四個(gè)級(jí)別逐漸增強(qiáng),每個(gè)級(jí)別解決一個(gè)問題。事務(wù)級(jí)別越高,性能越差
臟讀:又稱無效數(shù)據(jù)的讀出,是指在數(shù)據(jù)庫訪問中,事務(wù)T1將某一值修改,然后事務(wù)T2讀取該值,此后T1因?yàn)槟撤N原因撤銷對(duì)該值的修改,這就導(dǎo)致了T2所讀取到到的數(shù)據(jù)是無效的。臟讀就是指當(dāng)一個(gè)事務(wù)正在訪問數(shù)據(jù),并且對(duì)數(shù)據(jù)進(jìn)行了修改,而這種修改還沒有提交到數(shù)據(jù)庫中,這時(shí),另外一個(gè)事務(wù)也訪問這個(gè)數(shù)據(jù),然后使用了這個(gè)數(shù)據(jù)。
不可重復(fù)讀:是指在一個(gè)事務(wù)中,多次讀同一數(shù)據(jù)。在這個(gè)事務(wù)還沒有結(jié)束時(shí),另外一個(gè)事務(wù)也訪問該同一數(shù)據(jù)。那么,在第一個(gè)事務(wù)中的兩次讀數(shù)據(jù)之間,由于第二個(gè)事務(wù)的修改,那么第一個(gè)事務(wù)兩次讀到的數(shù)據(jù)可能是不一樣的。這樣就發(fā)生了在一個(gè)事務(wù)內(nèi)兩次讀到的數(shù)據(jù)是不一樣的,因此稱為是不可重復(fù)讀。
可重復(fù)讀:第一個(gè)事務(wù)兩次讀到的數(shù)據(jù)是一樣的。
幻讀:第一個(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ā)生了幻覺一樣。
本事務(wù)中第一次讀取出一行,做了一次更新后,另一個(gè)事務(wù)里提交的數(shù)據(jù)就出現(xiàn)了。也可以看做是一種幻讀。
一道筆試題:
小桔A在事務(wù)1中第一次讀取年齡20歲的員工總數(shù)為1000人,之后小桔B在事務(wù)2中增加了100名年齡20歲的新員工,之后小桔A在事務(wù)1中再次讀取年齡20歲的員工數(shù)發(fā)現(xiàn)總數(shù)變?yōu)?100人,屬于()?
A、臟讀
B、不可重復(fù)讀
C、幻讀
選C
幻讀的重點(diǎn)在于新增或者刪除
同樣的條件,第一次和第二次讀出來的記錄數(shù)不一樣
例子:
目前工資為1000的員工有10人
事務(wù)1,讀取所有工資為1000的員工,共讀取10條記錄。
這時(shí)另一個(gè)事務(wù)向employee表插入了一條員工記錄。
事務(wù)1再次讀取所有工資為1000的員工共讀取到了11條記錄,這就產(chǎn)生了幻像讀
不可重復(fù)讀的重點(diǎn)是修改
同樣的條件,你讀取過的數(shù)據(jù),再次讀取出來發(fā)現(xiàn)值不一樣了
例如:
在事務(wù)1中,Mary讀取了自己的工資為1000,操作并沒有完成。
在事務(wù)2中,這時(shí)財(cái)務(wù)人員修改了Mary的工資為2000,并提交了事務(wù)。
在事務(wù)1中,Mary再次讀取自己的工資時(shí),工資變味了2000。
臟讀:
臟讀就是指當(dāng)一個(gè)事務(wù)正在訪問數(shù)據(jù),并且對(duì)數(shù)據(jù)進(jìn)行了修改,而這種修改還沒有提交到數(shù)據(jù)庫中,這時(shí),另外一個(gè)事務(wù)也訪問這個(gè)數(shù)據(jù),然后使用了這個(gè)數(shù)據(jù)。
十一、 事務(wù)的特點(diǎn)有哪些?
ACID含義:
原子性(Atomicity):一個(gè)事務(wù)要么發(fā)生,要么不發(fā)生。
例如故障發(fā)生在write(A)和read(B)之間,則將有可能造成賬戶A的余額已經(jīng)減少50元錢,而賬戶B的余額卻沒有改變,憑空就少了50元錢。
一致性(Consistency):數(shù)據(jù)庫中數(shù)據(jù)的完整性,保證他們的正確性。
隔離性(Isolation):多個(gè)事務(wù)并發(fā)(同時(shí))執(zhí)行,互相不影響
持久性(Durability):每個(gè)事務(wù)成功執(zhí)行后對(duì)數(shù)據(jù)庫的修改是永久的。即使系統(tǒng)出現(xiàn)故障也不受影響。
十二、 觸發(fā)器是什么?
觸發(fā)器是SQL server提供給程序員和數(shù)據(jù)分析員來保證數(shù)據(jù)完整性的一種方法,它是與表事件相關(guān)的特殊存儲(chǔ)過程,它的執(zhí)行不是由程序調(diào)用,也不是手工啟動(dòng),而是由事件觸發(fā)。比如當(dāng)對(duì)一個(gè)表進(jìn)行操作(insert,delete,update)時(shí)就會(huì)激活它執(zhí)行。觸發(fā)器經(jīng)常用于加強(qiáng)數(shù)據(jù)的完整性約束和業(yè)務(wù)規(guī)則等。
在mysql中,創(chuàng)建觸發(fā)器語法如下:
Create trigger trigger_name trigger_time trigger_event on tbl_name for each row trigger_stmt其中:
Trigger_name:標(biāo)識(shí)觸發(fā)器名稱,用戶自行指定
trigger_time:標(biāo)識(shí)觸發(fā)時(shí)機(jī),取值為before或after
Trigger_event:標(biāo)識(shí)觸發(fā)事件,取值為insert,update或delete
Tbl_name:標(biāo)識(shí)建立觸發(fā)器的表名,即在哪張表上建立觸發(fā)器
Trigger_stmt:觸發(fā)器程序體,可以是一句sql語句,或者用begin和end包含的多條語句。
由此可見,可以建立6種觸發(fā)器,即:before insert、before update、before delete、after insert、after update、after delete。
注意:不能同時(shí)在一個(gè)表上建立2個(gè)相同類型的觸發(fā)器,因此在一個(gè)表上最多建立6個(gè)觸發(fā)器。
SQL Server包括三種常規(guī)類型的觸發(fā)器:DML觸發(fā)器、DDL觸發(fā)器和登錄觸發(fā)器
DML觸發(fā)器
當(dāng)數(shù)據(jù)庫中表中的數(shù)據(jù)發(fā)生變化時(shí),包括insert,update,delete任意操作,如果我們對(duì)該表寫了對(duì)應(yīng)的DML觸發(fā)器,那么該觸發(fā)器自動(dòng)執(zhí)行。DML觸發(fā)器的主要作用在于強(qiáng)制執(zhí)行業(yè)務(wù)規(guī)則,以及擴(kuò)展sql server約束,默認(rèn)值等。因?yàn)槲覀冎兰s束只能約束同一個(gè)表中的數(shù)據(jù),而觸發(fā)器中則可以執(zhí)行任意sql命令。
DDL觸發(fā)器
主要用于審核與規(guī)范對(duì)數(shù)據(jù)庫中表,觸發(fā)器,視圖等結(jié)構(gòu)上的操作。比如在修改表,修改列,新增表,新增列等。它在數(shù)據(jù)庫結(jié)構(gòu)發(fā)生變化時(shí)執(zhí)行,我們主要用它來記錄數(shù)據(jù)庫的修改過程,以及限制程序員對(duì)數(shù)據(jù)庫的修改,比如不允許刪除某些指定表等。
登錄觸發(fā)器
登錄觸發(fā)器將為響應(yīng)LOGIN事件而激發(fā)存儲(chǔ)過程。與SQL server實(shí)例建立用戶會(huì)話時(shí)將引發(fā)此事件。登陸觸發(fā)器將在登錄的身份驗(yàn)證階段完成之后且用戶會(huì)話實(shí)際建立之前激發(fā)。因此,來自觸發(fā)器內(nèi)部且通常將到達(dá)用戶的所有消息會(huì)傳送到SQL Server錯(cuò)誤日志。如果身份驗(yàn)證失敗,將不激發(fā)登錄觸發(fā)器。
觸發(fā)器的作用:
1、可在寫入數(shù)據(jù)表前,強(qiáng)制檢驗(yàn)或轉(zhuǎn)換數(shù)據(jù)
2、觸發(fā)器發(fā)生錯(cuò)誤時(shí),異動(dòng)的結(jié)果會(huì)被撤銷
3、部分?jǐn)?shù)據(jù)庫管理系統(tǒng)可以針對(duì)數(shù)據(jù)定義語言(DDL)使用觸發(fā)器,稱為DDL觸發(fā)器
4、可依照特定的情況,替換異動(dòng)的指令(INSTEAD OF)
DML觸發(fā)器又可分為After觸發(fā)器和Instead Of觸發(fā)器
(1)After觸發(fā)器:這類觸發(fā)器是在記錄已經(jīng)改變完之后(after),才會(huì)被激活執(zhí)行,它主要是用于記錄變更后的處理或檢查,一旦發(fā)現(xiàn)錯(cuò)誤,也可以用Rollback Transaction語句來回滾本次的操作。
(2)Instead of觸發(fā)器:這類觸發(fā)器一般是用來取代原本的操作,在記錄變更之前發(fā)生的,它并不去執(zhí)行原來SQL語句里的操作(insert、update、delete),而去執(zhí)行觸發(fā)器本身所定義的操作。
在SQL Server里,每個(gè)DML觸發(fā)器都分配有兩個(gè)特殊的表,一個(gè)是Inserted表,一個(gè)是Deleted表。它們兩個(gè)存在于數(shù)據(jù)庫服務(wù)器的內(nèi)存中,是由系統(tǒng)管理的邏輯表,是兩個(gè)臨時(shí)表,而不是真正存儲(chǔ)在數(shù)據(jù)庫中的物理表。用戶對(duì)這兩個(gè)表只有讀取的權(quán)限,沒有修改的權(quán)限。
這兩個(gè)表的結(jié)構(gòu)(主外鍵、字段、數(shù)據(jù)類型等)與觸發(fā)器所在數(shù)據(jù)表的結(jié)構(gòu)是完全一致的,當(dāng)觸發(fā)器的工作完成之后,這兩個(gè)表也將會(huì)從內(nèi)存中刪除。
Inserted和Deleted兩個(gè)表的作用:
Inserted:對(duì)于插入記錄操作來說,插入表里存放的是要插入的數(shù)據(jù);對(duì)于更新記錄操作來說,插入表里存放的是要更新的記錄。
Deleted:對(duì)于更新記錄操作來說,刪除表里存放的是被更新記錄;對(duì)于刪除記錄操作來說,刪除表里存入的是被刪除的舊記錄。
網(wǎng)上找的一張圖,可以幫助理解一下過程。
**注意事項(xiàng):** (1)只有表才可以支持觸發(fā)器,視圖和臨時(shí)表都不支持觸發(fā)器 (2)每個(gè)表的每個(gè)事件只支持一個(gè)觸發(fā)器,因此每個(gè)表最多支持6個(gè)觸發(fā)器(觸發(fā)器應(yīng)該相應(yīng)的行動(dòng)insert,delete,update,觸發(fā)器何時(shí)執(zhí)行before,after,2*3=6種) (3)單一觸發(fā)器不能與多個(gè)操作相關(guān) (4)觸發(fā)器不能更新和覆蓋,如果想更新一個(gè)觸發(fā)器必須先刪除,再創(chuàng)建。
十三、 為什么大部分?jǐn)?shù)據(jù)庫索引的實(shí)現(xiàn)使用B+樹而不是哈希表或紅黑樹之類的?
前言
動(dòng)態(tài)查找樹主要有:二叉查找樹,平衡二叉查找樹,紅黑樹,B- tree/B+ tree/B* tree。前三者是典型的二叉查找樹結(jié)構(gòu),其查詢的時(shí)間復(fù)雜度都與樹的深度相關(guān),那么降低樹的深度自然會(huì)提高查找效率。
磁盤存儲(chǔ)的知識(shí)
計(jì)算機(jī)存儲(chǔ)設(shè)備一般分為兩種:內(nèi)存儲(chǔ)器(main memory)和外存儲(chǔ)器(external memory)。內(nèi)存存取速度快,但容量小,價(jià)格昂貴,而且不能長期保存數(shù)據(jù)(在不通電情況下數(shù)據(jù)會(huì)消失)
索引一般以文件形式存儲(chǔ)在磁盤上,索引檢索需要磁盤I/O操作。與主存不同,磁盤I/O存在機(jī)械運(yùn)動(dòng)耗費(fèi),因此磁盤I/O的時(shí)間消耗是巨大的。從網(wǎng)上找了一張磁盤構(gòu)造圖如下所示:
除了最頂端和最底端的外側(cè)面不存儲(chǔ)數(shù)據(jù)之外,一共有4個(gè)面可以用來保存信息。當(dāng)磁盤驅(qū)動(dòng)器執(zhí)行讀/寫功能時(shí),盤片裝在一個(gè)主軸上,并繞主軸高速旋轉(zhuǎn),當(dāng)磁盤在讀/寫頭(又叫磁頭)下通過時(shí),就可以進(jìn)行數(shù)據(jù)的讀/寫了。
盤片被劃分成一系列同心環(huán),圓心是盤片中心,每個(gè)同心環(huán)叫做一個(gè)磁道,所有半徑相同的磁道組成一個(gè)柱面。磁道被沿半徑線劃分成一個(gè)個(gè)小的段,每個(gè)段叫做一個(gè)扇區(qū),每個(gè)扇區(qū)是磁盤的最小存儲(chǔ)單元。
當(dāng)需要從磁盤讀取數(shù)據(jù)時(shí),系統(tǒng)會(huì)將數(shù)據(jù)邏輯地址傳給磁盤,磁盤的控制電路按照尋址邏輯地址翻譯成物理地址,即確定要讀的數(shù)據(jù)在哪個(gè)磁道,哪個(gè)扇區(qū)。為了讀取這個(gè)扇區(qū)的數(shù)據(jù),需要將磁頭放到這個(gè)扇區(qū)上方,為了實(shí)現(xiàn)這一點(diǎn),磁頭需要移動(dòng)對(duì)準(zhǔn)相應(yīng)磁道,這個(gè)過程叫做尋道,所耗費(fèi)時(shí)間叫做尋道時(shí)間,然后磁盤旋轉(zhuǎn)將目標(biāo)扇區(qū)旋轉(zhuǎn)到磁頭下,這個(gè)過程耗費(fèi)的時(shí)間叫做旋轉(zhuǎn)時(shí)間。
**讀取數(shù)據(jù)順序:**先找到磁道(尋道時(shí)間)、然后旋轉(zhuǎn)到目標(biāo)扇區(qū)(旋轉(zhuǎn)時(shí)間)、然后讀取數(shù)據(jù)
局部性原理與磁盤預(yù)讀
由于存儲(chǔ)介質(zhì)的特性,磁盤本身存取就比主存慢很多,再加上機(jī)械運(yùn)動(dòng)耗費(fèi),磁盤的存取速度往往是主存的幾百分之一,因此為了提高效率,要盡量減少磁盤I/O。為了達(dá)到這個(gè)目的,磁盤往往不是嚴(yán)格按需讀取,而是每次都會(huì)預(yù)讀,即使只需要一個(gè)字節(jié),磁盤也會(huì)從這個(gè)位置開始,順序向后讀取一定長度的數(shù)據(jù)放入內(nèi)存。這樣做的理論依據(jù)是計(jì)算機(jī)科學(xué)中著名的局部性原理。
所謂的局部性原理是指:當(dāng)一個(gè)數(shù)據(jù)被用到時(shí),其附近的數(shù)據(jù)也通常會(huì)馬上被使用。程序運(yùn)行期間所需要的數(shù)據(jù)通常比較集中。由于磁盤順序讀取的效率很高(不需要尋道時(shí)間,只需很少的旋轉(zhuǎn)時(shí)間),因此對(duì)于具有局部性的程序來說,預(yù)讀可以提高I/O效率。
預(yù)讀的長度一般為頁的整倍數(shù)。頁式計(jì)算機(jī)管理存儲(chǔ)器的邏輯塊,硬件及操作系統(tǒng)往往將主存和磁盤存儲(chǔ)區(qū)分割為連續(xù)的大小相等的塊,每個(gè)存儲(chǔ)塊稱為一頁(在許多操作系統(tǒng)中,頁的大小通常為4K),主存和磁盤以頁為單位交換數(shù)據(jù)。當(dāng)程序要讀取的數(shù)據(jù)不在主存中時(shí),會(huì)觸發(fā)一個(gè)缺頁異常,此時(shí)系統(tǒng)會(huì)向磁盤發(fā)出讀盤信號(hào),磁盤會(huì)找到數(shù)據(jù)的起始位置并向后連續(xù)讀取一頁或幾頁載入內(nèi)存中,然后異常返回,程序繼續(xù)運(yùn)行。
為什么目前大部分?jǐn)?shù)據(jù)庫系統(tǒng)及文件系統(tǒng)都采用B樹或B+樹作為索引結(jié)構(gòu)?
1、紅黑樹
紅黑樹的定義:一種自平衡二叉查找樹,但是每個(gè)結(jié)點(diǎn)上增加一個(gè)存儲(chǔ)位表示結(jié)點(diǎn)的顏色,通過對(duì)任何一條從根到葉子的路徑上各個(gè)結(jié)點(diǎn)著色方式的限制,紅黑樹確保沒有一條路徑會(huì)比其他路徑長出兩倍,因而是接近平衡的。
紅黑樹的特性:
首先,作為一棵二叉查找樹,具備二叉查找樹的特性:
1、若任意結(jié)點(diǎn)的左子樹不空,則左子樹上所有結(jié)點(diǎn)的值均小于它的根節(jié)點(diǎn)的值。
2、若任意結(jié)點(diǎn)的右子樹不空,則右子樹上所有結(jié)點(diǎn)的值均大于它的根節(jié)點(diǎn)的值。
3、任意結(jié)點(diǎn)的左、右子樹也分別為二叉查找樹。
4、沒有鍵值相等的結(jié)點(diǎn)
紅黑樹的另外5個(gè)特性,保證了一棵n個(gè)結(jié)點(diǎn)的紅黑樹的高度始終保持在logn,也就解釋了“紅黑樹的查找、插入、刪除的時(shí)間復(fù)雜度最壞是o(logn)”
1、每個(gè)結(jié)點(diǎn)要么是紅的要么是黑的
2、根節(jié)點(diǎn)是黑色的
3、每個(gè)葉節(jié)點(diǎn)(葉節(jié)點(diǎn)即樹尾端NIL指針或NULL結(jié)點(diǎn))都是黑的
4、如果一個(gè)結(jié)點(diǎn)時(shí)紅的,那么它的兩個(gè)兒子都是黑的
5、對(duì)于任意結(jié)點(diǎn)而言,其到葉節(jié)點(diǎn)樹尾端NIL指針的每條路徑都包含相同數(shù)目的黑結(jié)點(diǎn)。
2、B樹
B樹與紅黑樹最大的不同在于,B樹的結(jié)點(diǎn)可以有許多子女,從幾個(gè)到幾千個(gè)。為什么又說B樹與紅黑樹很相似呢?因?yàn)榕c紅黑樹一樣,一棵含n個(gè)結(jié)點(diǎn)的B樹的高度也為o(lgn),但可能比一棵紅黑樹的高度小許多,因?yàn)樗姆种б蜃颖容^大。所以,B樹可以在o(logn)時(shí)間內(nèi),實(shí)現(xiàn)各種如插入、刪除等動(dòng)態(tài)集合操作。
這是一棵B樹,一顆關(guān)鍵字為英語中輔音字母的B樹,現(xiàn)在要從樹中查找字母R,一個(gè)內(nèi)結(jié)點(diǎn)x若含有n[x]個(gè)關(guān)鍵字,那么x將含有n[x]+1個(gè)子女,例如2個(gè)關(guān)鍵字D H的內(nèi)結(jié)點(diǎn)有3個(gè)子女,而含有3個(gè)關(guān)鍵字Q T X的內(nèi)結(jié)點(diǎn)有4個(gè)子女。所有的葉結(jié)點(diǎn)都處于相同的深度,背景為白色的結(jié)點(diǎn)為查找字母R時(shí)要檢查的結(jié)點(diǎn)。
一棵m階的B樹的特性如下:
1、每個(gè)結(jié)點(diǎn)至多有m棵子樹
2、除根節(jié)點(diǎn)外,其他每個(gè)分支結(jié)點(diǎn)至少有ceil(m/2)棵子樹(ceil是一個(gè)向上取整的函數(shù))
3、根節(jié)點(diǎn)至少有兩棵子樹(除非B樹只包含一個(gè)結(jié)點(diǎn))
4、所有葉結(jié)點(diǎn)在同一層上。B樹的葉節(jié)點(diǎn)可以看成一種外部結(jié)點(diǎn),不包含任何信息。
5、有j個(gè)孩子的非葉結(jié)點(diǎn)恰好有j-1個(gè)關(guān)鍵碼,關(guān)鍵碼按遞增次序排列。
3、B+樹
一棵m階的B+樹和m階的B樹的異同點(diǎn)在于:
1、B+樹:有n棵子樹的結(jié)點(diǎn)含有n個(gè)關(guān)鍵字,每個(gè)關(guān)鍵字不保存數(shù)據(jù),只用來索引,所有數(shù)據(jù)都保存在葉子結(jié)點(diǎn)
B樹:有n棵子樹的結(jié)點(diǎn)還有n-1個(gè)關(guān)鍵字。
2、B+樹:所有的葉子結(jié)點(diǎn)中包含了全部關(guān)鍵字的信息,及指向含有這些關(guān)鍵字記錄的指針,且葉子結(jié)點(diǎn)本身依關(guān)鍵字的大小自小而大的順序鏈接。
3、B+樹:所有的非終端結(jié)點(diǎn)可以看成是索引部分,結(jié)點(diǎn)中僅含有其子樹根節(jié)點(diǎn)中最大(或最小)的關(guān)鍵字。
通常在B+樹上有兩個(gè)頭指針,一個(gè)指向根節(jié)點(diǎn),一個(gè)指向關(guān)鍵字最小的葉子結(jié)點(diǎn)
為什么說B+樹比B樹更適合實(shí)際應(yīng)用中操作系統(tǒng)的文件索引和數(shù)據(jù)庫索引?
(1)B+樹的磁盤讀寫代碼更低
B+樹的內(nèi)部結(jié)點(diǎn)并沒有指向關(guān)鍵字具體信息的指針,因此其內(nèi)部結(jié)點(diǎn)相比B樹更小。如果把所有同一內(nèi)部結(jié)點(diǎn)的關(guān)鍵字存放在同一盤塊中,那么盤塊所能容納的關(guān)鍵字?jǐn)?shù)量也越多。一次性讀入內(nèi)存中的需要查找的關(guān)鍵字也就越多。相對(duì)來說IO讀寫次數(shù)也就降低了。
(2)B+樹的查詢效率更加穩(wěn)定
由于非終結(jié)點(diǎn)并不是最終指向文件內(nèi)容的結(jié)點(diǎn),而只是葉子結(jié)點(diǎn)中關(guān)鍵字的索引。所以任何關(guān)鍵字的查找必須走一條從根節(jié)點(diǎn)到葉子結(jié)點(diǎn)的路。所有關(guān)鍵字查詢的路徑長度相同,導(dǎo)致每一個(gè)數(shù)據(jù)的查詢效率相當(dāng)。
總結(jié)
- 上一篇: Labview实现画板
- 下一篇: linux cmake编译源码,linu