mysql count 条件_我以为我对MySql很了解,直到我面试了字节跳动
小濕來(lái)到字節(jié)跳動(dòng),在靜待,此時(shí)一位長(zhǎng)發(fā)飄飄的面試官走來(lái)。小濕心里想:哎啊,今天遇到個(gè)美女面試官,好好表現(xiàn)
面試官:小濕,我看你簡(jiǎn)歷上寫(xiě)了熟練掌握MySql和MySql的調(diào)優(yōu)是吧?
小濕:是的,面試官。
面試官:說(shuō)一下你在項(xiàng)目中如何使用MySql的?
小濕:增刪改查,沒(méi)了。
面試官:如何調(diào)優(yōu)的你是?
小濕:加索引,沒(méi)了。
面試官:我們公司的門你知道在哪里吧,用我送你嗎?
哈哈,上面場(chǎng)景是開(kāi)玩笑的當(dāng)然,言歸正傳,大家如果真遇到這種問(wèn)題如何回答?數(shù)據(jù)庫(kù)是如何調(diào)優(yōu)的?或者說(shuō)大家可能都清楚加索引是數(shù)據(jù)庫(kù)調(diào)優(yōu)方法之一,但是關(guān)于索引又知道多少呢?下面我們一起進(jìn)入主題
面試開(kāi)始
面試官:說(shuō)一下in關(guān)鍵字和exists關(guān)鍵字吧
小濕:好的,in關(guān)鍵字盡量用在內(nèi)表小的地方,exists關(guān)鍵字用在外表小的地方,如果用not in ,則是內(nèi)外表都全表掃描,無(wú)索引,效率低,可考慮使用not exists,也可以考慮用連接來(lái)優(yōu)化。(內(nèi)心OS,這能難得到我?)
接下來(lái)分析一波(面試回答問(wèn)題一定要條理清晰!)
in關(guān)鍵字是把外表和內(nèi)表做hash連接,先查詢內(nèi)表,再把內(nèi)表的結(jié)果和外表匹配,對(duì)外表使用索引(外表效率高,可以用大表),而內(nèi)表都需要查詢,使用in關(guān)鍵字可以加快效率。exists關(guān)鍵字是對(duì)外表做loop循環(huán),每次循環(huán)對(duì)內(nèi)表進(jìn)行查詢(對(duì)內(nèi)表可以使用索引,查詢效率高,可以用大表),而外表有多大都需要遍歷,使用exists關(guān)鍵字可以加快效率。
舉個(gè)例子:select * from A where A.id in (select id from B);對(duì)A表使用索引效率高,建議A為大表。select * from A where exists (select * from B where A.id=B.id);對(duì)B使用索引效率高,因?yàn)橥獗鞟總是要全表,而且要循環(huán),所以B表建議使用大表。
面試官:說(shuō)一下count吧
小濕:count關(guān)鍵字是用來(lái)進(jìn)行不為null的行數(shù)統(tǒng)計(jì)的,有三種用法分別是:count(列名)、count(常量)和count(*)。在《阿里巴巴Java開(kāi)發(fā)手冊(cè)》中強(qiáng)制要求不讓使用 count(列名)或 count(常量)來(lái)替代 count(*)
區(qū)別:列名、 常量 和 *這三個(gè)條件中,常量是一個(gè)固定值,肯定不為null。*可以理解為查詢整行,所以肯定也不為null,那么就只有列名的查詢結(jié)果有可能是null了,所以count(常量) 和 count(*)表示的是直接查詢符合條件的數(shù)據(jù)庫(kù)表的行數(shù)。而count(列名)表示的是查詢符合條件的列的值不為null的行數(shù)。count(*)是SQL92定義的標(biāo)準(zhǔn)統(tǒng)計(jì)行數(shù)的語(yǔ)法,因?yàn)樗菢?biāo)準(zhǔn)語(yǔ)法,所以mysql數(shù)據(jù)庫(kù)對(duì)他進(jìn)行過(guò)很多優(yōu)化
SQL92,是數(shù)據(jù)庫(kù)的一個(gè)ANSI/ISO標(biāo)準(zhǔn)。它定義了一種語(yǔ)言(SQL)以及數(shù)據(jù)庫(kù)的行為(事務(wù)、隔離級(jí)別等
面試官:你能說(shuō)一下這些優(yōu)化嗎?
小濕:面帶微笑,當(dāng)然可以的。這里的介紹要區(qū)分不同的執(zhí)行引擎,MySQL中比較常用的執(zhí)行引擎就是InnoDB和MyISAM。我們知道MyISAM不支持事務(wù),表級(jí)鎖,而InnoDB支持事務(wù),支持行級(jí)鎖。
因?yàn)镸yISAM是表級(jí)鎖,所以在一張表上的操作是串行執(zhí)行的。所以,MyISAM做了一個(gè)簡(jiǎn)單的優(yōu)化,那就是它可以把表的總行數(shù)單獨(dú)記錄下來(lái),如果從一張表中使用count(*)進(jìn)行查詢的時(shí)候,可以直接返回這個(gè)記錄下來(lái)的數(shù)值就可以了,當(dāng)然,前提是不能有where條件。為什么MyISAM可以這樣做呢?因?yàn)樗潜砑?jí)鎖,不會(huì)有并發(fā)的數(shù)據(jù)庫(kù)修改記錄的行為,查詢的行數(shù)是準(zhǔn)確的
對(duì)于InnoDB則不適合這種緩存操作了,它是支持事務(wù)和行級(jí)鎖,表的行數(shù)可能會(huì)被并發(fā)修改,那么緩存記錄下來(lái)的行數(shù)就不準(zhǔn)確了,那么InnoDB則不可避免的要進(jìn)行掃表了。于是從mysql8.0.13開(kāi)始,select count(*) 在掃表的過(guò)程中做了一些優(yōu)化,前提是查詢語(yǔ)句中不包含where或group by等條件。我們的目的只是為了統(tǒng)計(jì)總行數(shù),并不關(guān)心查到的具體值,所以可以選擇一個(gè)成本較低的索引進(jìn)行,節(jié)省時(shí)間。而且InnoDB中索引分為聚簇索引(主鍵索引)和非聚簇索引(非主鍵索引),聚簇索引的葉子節(jié)點(diǎn)中保存的是整行記錄,而非聚簇索引的葉子節(jié)點(diǎn)中保存的是該行記錄的主鍵的值。所以,相比之下,非聚簇索引要比聚簇索引小很多,所以MySQL會(huì)優(yōu)先選擇最小的非聚簇索引來(lái)掃表。所以,當(dāng)我們建表的時(shí)候,除了主鍵索引以外,創(chuàng)建一個(gè)非主鍵索引還是有必要的。
面試官:mysql中字段為什么要求定義為not null?
小濕:null值會(huì)占用更多的字節(jié),且會(huì)在程序中造成很多與預(yù)期不符的情況。
面試官:(此時(shí)面試官點(diǎn)了點(diǎn)頭,繼續(xù)微笑著說(shuō)到)你剛剛提到過(guò)引擎,除了你說(shuō)的兩點(diǎn)區(qū)別,還有別的嗎?
小濕:接下來(lái)我來(lái)分點(diǎn)介紹
- 上面剛剛介紹的,MyISAM不支持事務(wù),表級(jí)鎖,而InnoDB支持事務(wù),支持行級(jí)鎖
- InnoDB 支持外鍵,而 MyISAM 不支持。對(duì)一個(gè)包含外鍵的 InnoDB 表轉(zhuǎn)為 MYISAM 會(huì)失敗
- InnoDB 是聚集索引,MyISAM 是非聚集索引
面試官:那你能說(shuō)說(shuō)什么是索引嗎?
小濕:索引其實(shí)是一種數(shù)據(jù)結(jié)構(gòu),能夠幫助我們快速的檢索數(shù)據(jù)庫(kù)中的數(shù)據(jù)。在用法上索引大概分為以下幾類:
- 普通索引normal:僅僅加索查詢;
- 唯一索引unique:加索查詢,列值唯一,可以有NULL。
- 主鍵索引primary:加速查詢,列值唯一,不可以為NULL,表中只有一個(gè)。
- 組合索引:多列值組成一個(gè)索引,專門用于組合搜索,其效率大于索引合并
- 全文索引full text:對(duì)文本的內(nèi)容進(jìn)行分詞,進(jìn)行搜索
面試官:那索引具體底層是什么樣子的?(言外之意就是數(shù)據(jù)結(jié)構(gòu))
小濕:索引的數(shù)據(jù)結(jié)構(gòu)和具體存儲(chǔ)引擎的實(shí)現(xiàn)有關(guān),MySQL主要有兩種結(jié)構(gòu):Hash索引和B+ Tree索引,我們使用的是InnoDB引擎,默認(rèn)的是B+樹(shù)
面試官:為什么采用B+樹(shù)呢,和Hash索引比較如何?
小濕:好的,接下來(lái)我來(lái)詳細(xì)介紹下兩者:
面試官:關(guān)于B+樹(shù)的葉子節(jié)點(diǎn),可以存放哪些東西?
小濕:在B+樹(shù)的索引中,葉子節(jié)點(diǎn)可能存儲(chǔ)了當(dāng)前的key值,也可能存儲(chǔ)了當(dāng)前的key值以及整行的數(shù)據(jù),這就是聚簇索引和非聚簇索引。在InnoDB引擎中,只有主鍵是聚簇索引,如果沒(méi)有主鍵則挑選一個(gè)唯一鍵作為聚簇索引,如果沒(méi)有唯一鍵,則隱式的生成一個(gè)鍵來(lái)建立聚簇索引
面試官:聚簇索引和非聚簇索引特點(diǎn)?
小濕:聚簇索引和非聚簇索引,聚簇索引更快,因?yàn)橹麈I索引樹(shù)的葉子節(jié)點(diǎn)直接就是我們要查詢的整行數(shù)據(jù)了。而非主鍵索引的葉子節(jié)點(diǎn)是主鍵的值,查到主鍵的值以后,還需要再通過(guò)主鍵的值再進(jìn)行一次查詢。當(dāng)查詢使用局促索引的時(shí)候,在對(duì)應(yīng)的葉子結(jié)點(diǎn)上可以獲取到整行的數(shù)據(jù),不再需要回表查詢,而非聚簇索引則需要回表查詢。
面試官:那非聚簇索引一定要回表搜索嗎?
小濕:不一定,這涉及到查詢語(yǔ)句所要求的字段是否全部命中了索引,如果全部命中了索引,那么就不必再進(jìn)行回表查詢,即覆蓋索引。
覆蓋索引(covering index)指一個(gè)查詢語(yǔ)句的執(zhí)行只用從索引中就能夠取得,不必從數(shù)據(jù)表中讀取。也可以稱之為實(shí)現(xiàn)了索引覆蓋。 當(dāng)一條查詢語(yǔ)句符合覆蓋索引條件時(shí),MySQL只需要通過(guò)索引就可以返回查詢所需要的數(shù)據(jù),這樣避免了查到索引后再返回表操作,減少I/O提高效率。 如表covering_index_sample中有一個(gè)普通索引 idx_key1_key2(key1,key2)。當(dāng)我們通過(guò)SQL語(yǔ)句:select key2 from covering_index_sample where key1 = ‘keytest’;的時(shí)候,就可以通過(guò)覆蓋索引查詢,無(wú)需回表
此時(shí),面試官投來(lái)了一個(gè)肯定的眼神(表現(xiàn)不錯(cuò),繼續(xù)為難她一波),不過(guò)她好像沒(méi)打算就此放過(guò)我,果不其然,又來(lái)了第二波!
面試官:在建立索引的時(shí)候,你一般考慮哪些因素?
小濕:建立索引的時(shí)候一般要考慮字段的使用頻率,經(jīng)常作為查詢條件的字段比較適合索引。當(dāng)然也不能過(guò)度建立索引,因?yàn)樗饕彩钦紦?jù)內(nèi)存的,而且修改表會(huì)導(dǎo)致索引更新,所以在建立索引的時(shí)候也要考慮表結(jié)構(gòu)。
在一些場(chǎng)合使用聯(lián)合索引是比較好的效果,比如我們可以建立一個(gè)(學(xué)校-班級(jí)-ID)的聯(lián)合索引,這樣會(huì)比建立三個(gè)索引效果好,但是如果我們只使用其中一個(gè)索引ID不會(huì)走聯(lián)合索引,會(huì)導(dǎo)致全表掃描,所以要分業(yè)務(wù)情況。使用聯(lián)合索引時(shí)需要注意順序,盡量把區(qū)分度大的索引放在前面。
面試官:為什么建立聯(lián)合索引?(區(qū)分度大的索引放在前面)
小濕:在聯(lián)合索引使用中,如果想要命中索引需要按照建立索引時(shí)的字段順序挨個(gè)使用,否則無(wú)法命中索引。聯(lián)合索引中有個(gè)最左匹配原則,當(dāng)我們建立聯(lián)合索引(A,B,C),實(shí)際上已經(jīng)建立了(A)、(A,B)、(A,B,C)三個(gè)聯(lián)合索引。
比如我們上面說(shuō)的(學(xué)校-班級(jí)-ID)聯(lián)合索引,b+樹(shù)是按照從左到右的順序來(lái)建立搜索樹(shù)的,b+樹(shù)優(yōu)先比較學(xué)校來(lái)確定下一步的搜索方向,如果還未達(dá)到條件則繼續(xù)執(zhí)行搜索。如果只有學(xué)校字段,班級(jí)字段缺失,只能找到這個(gè)學(xué)校的所有字段,然后再匹配相應(yīng)ID的學(xué)生,此種情況無(wú)法用到聯(lián)合索引。
面試官:如何判斷創(chuàng)建的索引是否使用到,或者說(shuō)如何分析Sql語(yǔ)句?
小濕:我一般都是通過(guò)explain命令來(lái)查看語(yǔ)句的執(zhí)行計(jì)劃,使用explain關(guān)鍵字可以模擬優(yōu)化器執(zhí)行SQL查詢語(yǔ)句,從而知道MySQL是如何處理你的SQL語(yǔ)句的。分析你的查詢語(yǔ)句或是表結(jié)構(gòu)的性能瓶頸。
面試官:簡(jiǎn)單說(shuō)一下Explain的字段?
小濕:(下面是相關(guān)字段,沒(méi)必要全說(shuō),說(shuō)熟悉的即可)
- id:select查詢的序列號(hào),包含一組數(shù)字,表示查詢中執(zhí)行select子句或操作表的順序
- select_type:查詢的類型,主要是用于區(qū)別普通查詢、聯(lián)合查詢、子查詢等的復(fù)雜查詢
- table:指的就是當(dāng)前執(zhí)行的表
- type:type所顯示的是查詢使用了哪種類型。查詢性能從最好到最差依次是:system > const > eq_ref > ref > range > index > all,一般來(lái)說(shuō),得保證查詢至少達(dá)到range級(jí)別,最好能達(dá)到ref
- possible_keys 和 key:possible_keys 顯示可能應(yīng)用在這張表中的索引,一個(gè)或多個(gè)。查詢涉及到的字段上若存在索引,則該索引將被列出,但不一定被查詢實(shí)際使用。key則表示實(shí)際使用的索引,如果為NULL,則沒(méi)有使用索引。(可能原因包括沒(méi)有建立索引或索引失效)
- key_len:表示索引中使用的字節(jié)數(shù),可通過(guò)該列計(jì)算查詢中使用的索引的長(zhǎng)度,在不損失精確性的情況下,長(zhǎng)度越短越好
- ref:顯示索引的那一列被使用了,如果可能的話,最好是一個(gè)常數(shù)。哪些列或常量被用于查找索引列上的值
- rows:根據(jù)表統(tǒng)計(jì)信息及索引選用情況,大致估算出找到所需的記錄所需要讀取的行數(shù),也就是說(shuō),用的越少越好
- Extra:包含不適合在其他列中顯式但十分重要的額外信息
面試官:什么情況下針對(duì)列創(chuàng)建了索引,查詢的時(shí)候卻沒(méi)有使用?
小濕:比如索引列參與了數(shù)學(xué)運(yùn)算或者函數(shù)。字符串like時(shí)的左邊是通配符,類似于"%aa"這種,當(dāng)mysql分析全表掃描比使用索引快的時(shí)候不使用索引。
面試官:那你知道在MySQL 5.6中,對(duì)索引做了哪些優(yōu)化嗎?
小濕:好像知道有個(gè)索引下推,默認(rèn)是開(kāi)啟的。官方文檔中給的例子和解釋如下:
SELECT * FROM people WHERE zipcode=‘95054’ AND lastname LIKE ‘%etrunia%’ AND address LIKE ‘%Main Street%’people表中(zipcode,lastname,firstname)構(gòu)成一個(gè)索引,如果沒(méi)有使用索引下推技術(shù),則MySQL會(huì)通過(guò)zipcode='95054’從存儲(chǔ)引擎中查詢對(duì)應(yīng)的數(shù)據(jù),返回到MySQL服務(wù)端,然后MySQL服務(wù)端基于lastname LIKE '%etrunia%'和address LIKE '%Main Street%'來(lái)判斷數(shù)據(jù)是否符合條件。如果使用了索引下推技術(shù),則MYSQL首先會(huì)返回符合zipcode='95054’的索引,然后根據(jù)lastname LIKE '%etrunia%'和address LIKE '%Main Street%'來(lái)判斷索引是否符合條件。如果符合條件,則根據(jù)該索引來(lái)定位對(duì)應(yīng)的數(shù)據(jù),如果不符合,則直接reject掉。有了索引下推優(yōu)化,可以在有l(wèi)ike條件查詢的情況下,減少回表次數(shù)。
面試官:MySql的架構(gòu)流程了解嗎?
小濕:(聽(tīng)見(jiàn)這種問(wèn)題我就拿起筆來(lái)邊說(shuō)邊畫(huà)),客戶端會(huì)先通過(guò)連接器連接,然后查詢緩存中是否有我們想要的數(shù)據(jù),即是否緩存命中。命中則直接返回?cái)?shù)據(jù),否則進(jìn)入分析器和優(yōu)化器,分析Sql語(yǔ)句和優(yōu)化Sql語(yǔ)句,然后執(zhí)行器選擇相應(yīng)的引擎執(zhí)行
面試官:說(shuō)說(shuō)數(shù)據(jù)庫(kù)的事務(wù)~
小濕:事務(wù)是一系列的操作,他們要符合ACID特性
- 原子性(Atomicity):事務(wù)必須是原子工作單元,對(duì)于數(shù)據(jù)修改,要么全都執(zhí)行,要么全部不執(zhí)行
- 一致性(Consistency):系統(tǒng)(數(shù)據(jù)庫(kù))總是從一個(gè)一致性的狀態(tài)轉(zhuǎn)移到另一個(gè)一致性的狀態(tài),不會(huì)存在中間狀態(tài)
- 隔離性(Isolation):一個(gè)事務(wù)在完全提交之前,對(duì)其他事務(wù)是不可見(jiàn)的
- 持久性(Durability):一旦事務(wù)提交,那么就永遠(yuǎn)是這樣子了,哪怕系統(tǒng)崩潰也不會(huì)影響到這個(gè)事務(wù)的結(jié)果
面試官:事務(wù)是否存在問(wèn)題呢在并發(fā)情況下?
小濕:事務(wù)在并發(fā)下存在臟讀、不可重復(fù)讀、虛讀等問(wèn)題
- 臟讀:事務(wù)A讀取到事務(wù)B未提交的數(shù)據(jù),結(jié)果事務(wù)B回滾了,造成錯(cuò)誤
- 不可重復(fù)讀:事務(wù)A執(zhí)行中,讀取數(shù)據(jù)num=10,此時(shí)事務(wù)B執(zhí)行完成并提交,修改了num=11。事務(wù)A再讀取num為11,這種情況叫做不可重復(fù)讀
- 虛讀:事務(wù)A讀取了一個(gè)范圍的數(shù)據(jù)(比如10<num<20),讀取到3條,結(jié)果事務(wù)B插入了一條數(shù)據(jù)成功提交,事務(wù)A讀取到這個(gè)范圍變成4條,即虛讀
- 不可重復(fù)讀的重點(diǎn)是修改,同樣的條件,你讀取過(guò)的數(shù)據(jù),再次讀取出來(lái)發(fā)現(xiàn)值不一樣;(主要在于update和delete)幻讀的重點(diǎn)在于新增或者刪除,同樣的條件,第 1 次和第 2 次讀出來(lái)的記錄數(shù)不一樣。(主要在于insert)
面試官:如何解決這些問(wèn)題呢?
小濕:為了解決以上事務(wù)并發(fā)時(shí)出現(xiàn)的一系列問(wèn)題,就需要設(shè)置事務(wù)的隔離級(jí)別。隔離級(jí)別就是多個(gè)線程開(kāi)啟各自事務(wù)操作數(shù)據(jù)庫(kù)中數(shù)據(jù)時(shí),數(shù)據(jù)庫(kù)系統(tǒng)要負(fù)責(zé)隔離操作,以保證各個(gè)線程在獲取數(shù)據(jù)時(shí)的準(zhǔn)確性
MySql中定義了4中隔離級(jí)別:
- 未提交讀(READ UNCOMMITTED):事務(wù)A可以讀取到事務(wù)B未提交的數(shù)據(jù)。最低級(jí)別,會(huì)造成臟讀的情況
- 已提交讀(READ COMMITTED):事務(wù)A只能讀取到事務(wù)B已經(jīng)提交的數(shù)據(jù),解決了臟讀的問(wèn)題,但是存在不可重復(fù)讀和虛讀的問(wèn)題
- 可重復(fù)讀(REPEATABLE READ):解決了事務(wù)A在執(zhí)行中前后讀取數(shù)據(jù)不一致的問(wèn)題,即不可重復(fù)讀的問(wèn)題,不會(huì)出現(xiàn)剛剛讀取num=10,過(guò)會(huì)再讀取num變?yōu)?1的情況。但是還是會(huì)存在虛讀的問(wèn)題,即事務(wù)A讀取一個(gè)范圍的數(shù)據(jù)量可能會(huì)發(fā)生變化造成“幻覺(jué)”
- 可串行化(SERIALIZABLE):這是最高的隔離級(jí)別,可以解決上面提到的所有問(wèn)題,因?yàn)樗麖?qiáng)制將所以的操作串行執(zhí)行,這會(huì)導(dǎo)致并發(fā)性能極速下降,因此也不是很常用
在MySQL數(shù)據(jù)庫(kù)中,支持上面四種隔離級(jí)別,默認(rèn)的為Repeatable read (可重復(fù)讀);而在Oracle數(shù)據(jù)庫(kù)中,只支持Serializable (串行化)級(jí)別和Read committed (讀已提交)這兩種級(jí)別,其中默認(rèn)的為Read committed級(jí)別
面試官:能不能詳細(xì)介紹下MySql是如何控制隔離級(jí)別的?
小濕:(還要詳細(xì),上面的難道還不夠?)是通過(guò)排它鎖和共享鎖。
- 排它鎖:被加鎖的對(duì)象只能被持有鎖的事務(wù)讀取和修改,其他事務(wù)無(wú)法在該對(duì)象上加其他鎖,也不能讀取和修改該對(duì)象
- 共享鎖:被加鎖的對(duì)象可以被持鎖事務(wù)讀取,但是不能被修改,其他事務(wù)也可以在上面再加共享鎖
在對(duì)不論什么數(shù)據(jù)進(jìn)行讀操作之前要申請(qǐng)并獲得S鎖(共享鎖,其他事務(wù)能夠繼續(xù)加共享鎖,但不能加排它鎖),在進(jìn)行寫(xiě)操作之前要申請(qǐng)并獲得X鎖(排它鎖,其他事務(wù)不能再獲得不論什么鎖)。加鎖不成功,則事務(wù)進(jìn)入等待狀態(tài),直到加鎖成功才繼續(xù)運(yùn)行。
面試官:你剛剛提到了數(shù)據(jù)庫(kù)的鎖,簡(jiǎn)單說(shuō)一下鎖吧
小濕:對(duì)數(shù)據(jù)的操作其實(shí)只有兩種,也就是讀和寫(xiě),而數(shù)據(jù)庫(kù)在實(shí)現(xiàn)鎖時(shí),也會(huì)對(duì)這兩種操作使用不同的鎖;InnoDB 實(shí)現(xiàn)了標(biāo)準(zhǔn)的行級(jí)鎖,也就是共享鎖(Shared Lock)和排它鎖(Exclusive Lock)。
共享鎖(讀鎖),允許事務(wù)讀一行數(shù)據(jù)。排它鎖(寫(xiě)鎖),允許事務(wù)刪除或更新一行數(shù)據(jù)。而它們的名字也暗示著各自的另外一個(gè)特性,共享鎖之間是兼容的,而互斥鎖與其他任意鎖都不兼容,如下圖
Lock鎖根據(jù)粒度主要分為表鎖、頁(yè)鎖和行鎖。不同的存儲(chǔ)引擎擁有的鎖粒度都不同
面試官:那悲觀鎖和樂(lè)觀鎖了解嗎
小濕:悲觀鎖和樂(lè)觀鎖是一種思想,一種處理方式,不可和上面的鎖機(jī)制(表鎖,行鎖,排他鎖,共享鎖)混為一談
- 悲觀鎖:即對(duì)于數(shù)據(jù)的處理持悲觀態(tài)度,總認(rèn)為會(huì)發(fā)生并發(fā)沖突,獲取和修改數(shù)據(jù)時(shí),別人會(huì)修改數(shù)據(jù)。所以在整個(gè)數(shù)據(jù)處理過(guò)程中,需要將數(shù)據(jù)鎖定。悲觀鎖的實(shí)現(xiàn),通常依靠數(shù)據(jù)庫(kù)提供的鎖機(jī)制實(shí)現(xiàn),比如mysql的排他鎖,select .... for update來(lái)實(shí)現(xiàn)悲觀鎖
- 樂(lè)觀鎖:顧名思義,就是對(duì)數(shù)據(jù)的處理持樂(lè)觀態(tài)度,樂(lè)觀的認(rèn)為數(shù)據(jù)一般情況下不會(huì)發(fā)生沖突,只有提交數(shù)據(jù)更新時(shí),才會(huì)對(duì)數(shù)據(jù)是否沖突進(jìn)行檢測(cè)。如果發(fā)現(xiàn)沖突了,則返回錯(cuò)誤信息給用戶,讓用戶自已決定如何操作。樂(lè)觀鎖的實(shí)現(xiàn)不依靠數(shù)據(jù)庫(kù)提供的鎖機(jī)制,需要我們自已實(shí)現(xiàn),實(shí)現(xiàn)方式一般是記錄數(shù)據(jù)版本,一種是通過(guò)版本號(hào),一種是通過(guò)時(shí)間戳。
給表加一個(gè)版本號(hào)或時(shí)間戳的字段,讀取數(shù)據(jù)時(shí),將版本號(hào)一同讀出,數(shù)據(jù)更新時(shí),將版本號(hào)加1。當(dāng)我們提交數(shù)據(jù)更新時(shí),判斷當(dāng)前的版本號(hào)與第一次讀取出來(lái)的版本號(hào)是否相等。如果相等,則予以更新,否則認(rèn)為數(shù)據(jù)過(guò)期,拒絕更新,讓用戶重新操作。
面試官:數(shù)據(jù)庫(kù)一個(gè)連接多久,每次都要釋放嗎?(言外之意就是數(shù)據(jù)庫(kù)的池化思想。)
小濕:數(shù)據(jù)庫(kù)連接是一種有限的昂貴的資源,對(duì)數(shù)據(jù)庫(kù)連接的管理能影響到整個(gè)應(yīng)用程序的伸縮性和健壯性,數(shù)據(jù)庫(kù)連接池正式針對(duì)這個(gè)問(wèn)題提出來(lái)的。數(shù)據(jù)庫(kù)連接池負(fù)責(zé)分配、管理和釋放數(shù)據(jù)庫(kù)連接,它允許應(yīng)用程序重復(fù)使用一個(gè)現(xiàn)有的數(shù)據(jù)庫(kù)連接,而不是重新建立一個(gè)。(數(shù)據(jù)庫(kù)連接池思想和線程池思想一樣)常用的三種連接池:
- C3p0連接池:開(kāi)源的JDBC連接池,實(shí)現(xiàn)了數(shù)據(jù)源和JNDI綁定,支持JDBC3規(guī)范和JDBC2的標(biāo)準(zhǔn)擴(kuò)展。目前使用它的開(kāi)源項(xiàng)目有Hibernate、Spring等。單線程,性能較差,適用于小型系統(tǒng),代碼600KB左右
- Dbcp連接池:由Apache開(kāi)發(fā)的一個(gè)Java數(shù)據(jù)庫(kù)連接池項(xiàng)目, Tomcat使用的連接池組件就是DBCP。預(yù)先將數(shù)據(jù)庫(kù)連接放在內(nèi)存中,應(yīng)用程序需要建立數(shù)據(jù)庫(kù)連接時(shí)直接到連接池中申請(qǐng)一個(gè)就行,用完再放回。單線程,并發(fā)量低,性能不好,適用于小型系統(tǒng)
- Druid連接池:Druid不僅是一個(gè)數(shù)據(jù)庫(kù)連接池,還包含一個(gè)ProxyDriver、一系列內(nèi)置的JDBC組件庫(kù)、一個(gè)SQL Parser
面試官:MySql數(shù)據(jù)丟失了怎么辦?(持久化機(jī)制)
小濕:這個(gè)我記得在InnoDB中有個(gè)redo 日志是用來(lái)保證 MySQL 持久化功能的。MySql的操作是要寫(xiě)入到日志中 ,并不會(huì)直接刷新到硬盤上進(jìn)行持久化。如果我們每一次的操作都要寫(xiě)入到硬盤中再更新,整個(gè)過(guò)程IO成本、查找成本都很高。
日志即起到一個(gè)中間轉(zhuǎn)折的作用,當(dāng)有一條記錄需要更新的時(shí)候,InnoDB 引擎就會(huì)先把記錄寫(xiě)到 redo log(粉板)里面,并更新內(nèi)存,這個(gè)時(shí)候更新就算完成了。同時(shí),InnoDB 引擎會(huì)在適當(dāng)?shù)臅r(shí)候,將這個(gè)操作記錄更新到磁盤里面,而這個(gè)更新往往是在系統(tǒng)比較空閑的時(shí)候做
面試官:今天的面試先到這兒吧,你的MySQL掌握的還不錯(cuò),明天有時(shí)間嗎?進(jìn)行下一輪面試
都這么為難我了,還不直接給我發(fā)offer??
好了,回家洗洗睡吧,準(zhǔn)備下期繼續(xù)面
了解更多技術(shù)干貨,關(guān)注公眾號(hào)【程序控】,我是小濕,一個(gè)有趣的靈魂!下期見(jiàn)
http://weixin.qq.com/r/8z8SCtzEdYEKrZhp92rh (二維碼自動(dòng)識(shí)別)
總結(jié)
以上是生活随笔為你收集整理的mysql count 条件_我以为我对MySql很了解,直到我面试了字节跳动的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 无法读取内存属于错误吗_深入了解 Jav
- 下一篇: python怎么连接mysql数据库_p