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

歡迎訪問 生活随笔!

生活随笔

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

数据库

数据库知识点梳理

發(fā)布時(shí)間:2023/12/31 数据库 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数据库知识点梳理 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

數(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記錄如下

aIDaNum
1a20050111
2a20050112
3a20050113
4a20050114
5a20050115

表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類型。
![](https://imgconvert.csdnimg.cn/aHR0cDovL2ltZy5ibG9nLmNzZG4ubmV0LzIwMTcwNDMwMjA1MDM5NTU2?x-oss-process=image/format,png)

三、 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é)果傳遞給主查詢,如下所示:

SELECT* FROM customerinfo WHERE customerID NOT in (SELECT customerid FROM salesinfo)

如果使用連接(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ù)目要相同。
例子:

Select name, phone from client union Select name, birthdate from author union Select name, supplier from product

(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)。
例子:

BEGIN:INSERT INTO salesinfo SET customerid = 14;UPDATE inventory SET quantity = 11 WHERE item=‘book’; COMMIT;

事務(wù)的另一個(gè)重要作用是當(dāng)多個(gè)用戶同時(shí)使用相同的數(shù)據(jù)源時(shí),它可以利用鎖定數(shù)據(jù)庫的方法來為用戶提供一種安全的訪問方式,這樣可以保證用戶的操作不被其他的用戶所干擾。

(5)鎖定表
通過鎖定表來防止其他的訪問對(duì)我們正在操作的表進(jìn)行插入、更新或者刪除的操作。
例子:

LOCK TABLE inventory WRITE SELECT quantity FROM inventory WHERE item=‘book’; … UPDATE inventory SET Quantity=11 WHERE Item=‘book’; UNLOCKTABLES

這里,我們用一個(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ì)比較表中的每一條記錄

SELECT * FROM books WHERE name like “MYSQL%”

但是如果換用下面的查詢,返回的結(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ì)劃的局限

  • explain不會(huì)告訴你關(guān)于觸發(fā)器、存儲(chǔ)過程的信息或用戶自定義函數(shù)對(duì)查詢的影響情況。
  • explain不考慮各種cache
  • explain不能顯示mysql在執(zhí)行查詢時(shí)所做的優(yōu)化工作
  • 部分統(tǒng)計(jì)信息是估算的,并非精確值
  • explain只能解釋select操作,其他操作要重寫為select后查看執(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)中建立索引主要有以下作用:

  • 大大加快數(shù)據(jù)的檢索速度(最主要原因,)
  • 保證數(shù)據(jù)記錄的唯一性(通過建立唯一性索引,可以保證數(shù)據(jù)庫中每一行數(shù)據(jù)的唯一性)
  • 可以加速表和表之間的連接,實(shí)現(xiàn)表與表之間的參照完整性
  • 在使用order by、group by子句(分組和排序子句)進(jìn)行數(shù)據(jù)檢索時(shí),利用索引可以顯著減少分組和排序的時(shí)間。
  • (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)建索引的辦法:

  • 直接創(chuàng)建索引
    例如使用create index語句或者使用創(chuàng)建索引向?qū)?/li>
  • 間接創(chuàng)建索引
    例如在表中定義主鍵約束或者唯一性鍵約束時(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ǔ)引擎,而且禁止使用臨時(shí)表。
  • 數(shù)據(jù)表的存儲(chǔ)引擎只能為InnoDB。
  • 外鍵列和參照列必須具有相似的數(shù)據(jù)類型。其中數(shù)字的長度或是否有符號(hào)位必須相同;而字符的長度則可以不同。
  • 外鍵列和參照列必須創(chuàng)建索引。如果外鍵列不存在索引的話,MySQL將自動(dòng)創(chuàng)建索引。
  • 六、 什么是存儲(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í)別?

    隔離級(jí)別臟讀不可重復(fù)讀幻讀
    未提交讀可能可能可能
    已提交讀不可能可能可能
    可重復(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ì)于刪除記錄操作來說,刪除表里存入的是被刪除的舊記錄。

    | 激活觸發(fā)器的操作 | Inserted表 | Deleted表 | | -- | -- | -- | | Insert | 存放要插入到表中的數(shù)據(jù) | 無 | | Update | 存放要更新到表中的數(shù)據(jù) | 存放被更新的記錄 | | Delete | 無 | 存放要?jiǎng)h除的記錄 |
    網(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é)

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

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