跳槽必備:MySQL高頻面試題,都在這了!
1. 什么是索引?
索引是一種數(shù)據(jù)結(jié)構(gòu),可以幫助我們快速的進(jìn)行數(shù)據(jù)的查找.
2. 索引是個(gè)什么樣的數(shù)據(jù)結(jié)構(gòu)呢?
索引的數(shù)據(jù)結(jié)構(gòu)和具體存儲(chǔ)引擎的實(shí)現(xiàn)有關(guān), 在MySQL中使用較多的索引有Hash索引,B+樹(shù)索引等,而我們經(jīng)常使用的InnoDB存儲(chǔ)引擎的默認(rèn)索引實(shí)現(xiàn)為:B+樹(shù)索引.
3. Hash索引和B+樹(shù)所有有什么區(qū)別或者說(shuō)優(yōu)劣呢?
首先要知道Hash索引和B+樹(shù)索引的底層實(shí)現(xiàn)原理:
hash索引底層就是hash表,進(jìn)行查找時(shí),調(diào)用一次hash函數(shù)就可以獲取到相應(yīng)的鍵值,之后進(jìn)行回表查詢獲得實(shí)際數(shù)據(jù).B+樹(shù)底層實(shí)現(xiàn)是多路平衡查找樹(shù).對(duì)于每一次的查詢都是從根節(jié)點(diǎn)出發(fā),查找到葉子節(jié)點(diǎn)方可以獲得所查鍵值,然后根據(jù)查詢判斷是否需要回表查詢數(shù)據(jù).
那么可以看出他們有以下的不同:
hash索引進(jìn)行等值查詢更快(一般情況下),但是卻無(wú)法進(jìn)行范圍查詢.
因?yàn)樵趆ash索引中經(jīng)過(guò)hash函數(shù)建立索引之后,索引的順序與原順序無(wú)法保持一致,不能支持范圍查詢.而B(niǎo)+樹(shù)的的所有節(jié)點(diǎn)皆遵循(左節(jié)點(diǎn)小于父節(jié)點(diǎn),右節(jié)點(diǎn)大于父節(jié)點(diǎn),多叉樹(shù)也類似),天然支持范圍.
hash索引不支持使用索引進(jìn)行排序,原理同上.
hash索引不支持模糊查詢以及多列索引的最左前綴匹配.原理也是因?yàn)閔ash函數(shù)的不可預(yù)測(cè).AAAA和AAAAB的索引沒(méi)有相關(guān)性.
hash索引任何時(shí)候都避免不了回表查詢數(shù)據(jù),而B(niǎo)+樹(shù)在符合某些條件(聚簇索引,覆蓋索引等)的時(shí)候可以只通過(guò)索引完成查詢.
hash索引雖然在等值查詢上較快,但是不穩(wěn)定.性能不可預(yù)測(cè),當(dāng)某個(gè)鍵值存在大量重復(fù)的時(shí)候,發(fā)生hash碰撞,此時(shí)效率可能極差.而B(niǎo)+樹(shù)的查詢效率比較穩(wěn)定,對(duì)于所有的查詢都是從根節(jié)點(diǎn)到葉子節(jié)點(diǎn),且樹(shù)的高度較低.
因此,在大多數(shù)情況下,直接選擇B+樹(shù)索引可以獲得穩(wěn)定且較好的查詢速度.而不需要使用hash索引.
4. 上面提到了B+樹(shù)在滿足聚簇索引和覆蓋索引的時(shí)候不需要回表查詢數(shù)據(jù),什么是聚簇索引?
在B+樹(shù)的索引中,葉子節(jié)點(diǎn)可能存儲(chǔ)了當(dāng)前的key值,也可能存儲(chǔ)了當(dāng)前的key值以及整行的數(shù)據(jù),這就是聚簇索引和非聚簇索引. 在InnoDB中,只有主鍵索引是聚簇索引,如果沒(méi)有主鍵,則挑選一個(gè)唯一鍵建立聚簇索引.如果沒(méi)有唯一鍵,則隱式的生成一個(gè)鍵來(lái)建立聚簇索引.
當(dāng)查詢使用聚簇索引時(shí),在對(duì)應(yīng)的葉子節(jié)點(diǎn),可以獲取到整行數(shù)據(jù),因此不用再次進(jìn)行回表查詢.
5. 非聚簇索引一定會(huì)回表查詢嗎?
不一定,這涉及到查詢語(yǔ)句所要求的字段是否全部命中了索引,如果全部命中了索引,那么就不必再進(jìn)行回表查詢.
舉個(gè)簡(jiǎn)單的例子,假設(shè)我們?cè)趩T工表的年齡上建立了索引,那么當(dāng)進(jìn)行select age from employee where age < 20
的查詢時(shí),在索引的葉子節(jié)點(diǎn)上,已經(jīng)包含了age信息,不會(huì)再次進(jìn)行回表查詢.
6. 在建立索引的時(shí)候,都有哪些需要考慮的因素呢?
建立索引的時(shí)候一般要考慮到字段的使用頻率,經(jīng)常作為條件進(jìn)行查詢的字段比較適合.如果需要建立聯(lián)合索引的話,還需要考慮聯(lián)合索引中的順序.此外也要考慮其他方面,比如防止過(guò)多的所有對(duì)表造成太大的壓力.這些都和實(shí)際的表結(jié)構(gòu)以及查詢方式有關(guān).
7. 聯(lián)合索引是什么?為什么需要注意聯(lián)合索引中的順序?
MySQL可以使用多個(gè)字段同時(shí)建立一個(gè)索引,叫做聯(lián)合索引.在聯(lián)合索引中,如果想要命中索引,需要按照建立索引時(shí)的字段順序挨個(gè)使用,否則無(wú)法命中索引.
具體原因?yàn)?
MySQL使用索引時(shí)需要索引有序,假設(shè)現(xiàn)在建立了"name,age,school"的聯(lián)合索引,那么索引的排序?yàn)? 先按照name排序,如果name相同,則按照age排序,如果age的值也相等,則按照school進(jìn)行排序.
當(dāng)進(jìn)行查詢時(shí),此時(shí)索引僅僅按照name嚴(yán)格有序,因此必須首先使用name字段進(jìn)行等值查詢,之后對(duì)于匹配到的列而言,其按照age字段嚴(yán)格有序,此時(shí)可以使用age字段用做索引查找,,,以此類推.因此在建立聯(lián)合索引的時(shí)候應(yīng)該注意索引列的順序,一般情況下,將查詢需求頻繁或者字段選擇性高的列放在前面.此外可以根據(jù)特例的查詢或者表結(jié)構(gòu)進(jìn)行單獨(dú)的調(diào)整.
8. 創(chuàng)建的索引有沒(méi)有被使用到?或者說(shuō)怎么才可以知道這條語(yǔ)句運(yùn)行很慢的原因?
MySQL提供了explain命令來(lái)查看語(yǔ)句的執(zhí)行計(jì)劃,MySQL在執(zhí)行某個(gè)語(yǔ)句之前,會(huì)將該語(yǔ)句過(guò)一遍查詢優(yōu)化器,之后會(huì)拿到對(duì)語(yǔ)句的分析,也就是執(zhí)行計(jì)劃,其中包含了許多信息.可以通過(guò)其中和索引有關(guān)的信息來(lái)分析是否命中了索引,例如possilbe_key,key,key_len等字段,分別說(shuō)明了此語(yǔ)句可能會(huì)使用的索引,實(shí)際使用的索引以及使用的索引長(zhǎng)度.
9. 那么在哪些情況下會(huì)發(fā)生針對(duì)該列創(chuàng)建了索引但是在查詢的時(shí)候并沒(méi)有使用呢?
使用不等于查詢,
列參與了數(shù)學(xué)運(yùn)算或者函數(shù)
在字符串like時(shí)左邊是通配符.類似于'%aaa'.
當(dāng)mysql分析全表掃描比使用索引快的時(shí)候不使用索引.
當(dāng)使用聯(lián)合索引,前面一個(gè)條件為范圍查詢,后面的即使符合最左前綴原則,也無(wú)法使用索引.
以上情況,MySQL無(wú)法使用索引.
事務(wù)相關(guān)
1. 什么是事務(wù)?
理解什么是事務(wù)最經(jīng)典的就是轉(zhuǎn)賬的栗子,相信大家也都了解,這里就不再說(shuō)一邊了.
事務(wù)是一系列的操作,他們要符合ACID特性.最常見(jiàn)的理解就是:事務(wù)中的操作要么全部成功,要么全部失敗.但是只是這樣還不夠的.
2. ACID是什么?可以詳細(xì)說(shuō)一下嗎?
A=Atomicity
原子性,就是上面說(shuō)的,要么全部成功,要么全部失敗.不可能只執(zhí)行一部分操作.
C=Consistency
系統(tǒng)(數(shù)據(jù)庫(kù))總是從一個(gè)一致性的狀態(tài)轉(zhuǎn)移到另一個(gè)一致性的狀態(tài),不會(huì)存在中間狀態(tài).
I=Isolation
隔離性: 通常來(lái)說(shuō):一個(gè)事務(wù)在完全提交之前,對(duì)其他事務(wù)是不可見(jiàn)的.注意前面的通常來(lái)說(shuō)加了紅色,意味著有例外情況.
D=Durability
持久性,一旦事務(wù)提交,那么就永遠(yuǎn)是這樣子了,哪怕系統(tǒng)崩潰也不會(huì)影響到這個(gè)事務(wù)的結(jié)果.
3. 同時(shí)有多個(gè)事務(wù)在進(jìn)行會(huì)怎么樣呢?
多事務(wù)的并發(fā)進(jìn)行一般會(huì)造成以下幾個(gè)問(wèn)題:
臟讀: A事務(wù)讀取到了B事務(wù)未提交的內(nèi)容,而B(niǎo)事務(wù)后面進(jìn)行了回滾.
不可重復(fù)讀: 當(dāng)設(shè)置A事務(wù)只能讀取B事務(wù)已經(jīng)提交的部分,會(huì)造成在A事務(wù)內(nèi)的兩次查詢,結(jié)果竟然不一樣,因?yàn)樵诖似陂gB事務(wù)進(jìn)行了提交操作.
幻讀: A事務(wù)讀取了一個(gè)范圍的內(nèi)容,而同時(shí)B事務(wù)在此期間插入了一條數(shù)據(jù).造成"幻覺(jué)".
4. 怎么解決這些問(wèn)題呢?MySQL的事務(wù)隔離級(jí)別了解嗎?
MySQL的四種隔離級(jí)別如下:
未提交讀(READ UNCOMMITTED)
這就是上面所說(shuō)的例外情況了,這個(gè)隔離級(jí)別下,其他事務(wù)可以看到本事務(wù)沒(méi)有提交的部分修改.因此會(huì)造成臟讀的問(wèn)題(讀取到了其他事務(wù)未提交的部分,而之后該事務(wù)進(jìn)行了回滾).
這個(gè)級(jí)別的性能沒(méi)有足夠大的優(yōu)勢(shì),但是又有很多的問(wèn)題,因此很少使用.
已提交讀(READ COMMITTED)
其他事務(wù)只能讀取到本事務(wù)已經(jīng)提交的部分.這個(gè)隔離級(jí)別有 不可重復(fù)讀的問(wèn)題,在同一個(gè)事務(wù)內(nèi)的兩次讀取,拿到的結(jié)果竟然不一樣,因?yàn)榱硗庖粋€(gè)事務(wù)對(duì)數(shù)據(jù)進(jìn)行了修改.
REPEATABLE READ(可重復(fù)讀)
可重復(fù)讀隔離級(jí)別解決了上面不可重復(fù)讀的問(wèn)題(看名字也知道),但是仍然有一個(gè)新問(wèn)題,就是 幻讀,當(dāng)你讀取id> 10 的數(shù)據(jù)行時(shí),對(duì)涉及到的所有行加上了讀鎖,此時(shí)例外一個(gè)事務(wù)新插入了一條id=11的數(shù)據(jù),因?yàn)槭切虏迦氲?所以不會(huì)觸發(fā)上面的鎖的排斥,那么進(jìn)行本事務(wù)進(jìn)行下一次的查詢時(shí)會(huì)發(fā)現(xiàn)有一條id=11的數(shù)據(jù),而上次的查詢操作并沒(méi)有獲取到,再進(jìn)行插入就會(huì)有主鍵沖突的問(wèn)題.
SERIALIZABLE(可串行化)
這是最高的隔離級(jí)別,可以解決上面提到的所有問(wèn)題,因?yàn)樗麖?qiáng)制將所以的操作串行執(zhí)行,這會(huì)導(dǎo)致并發(fā)性能極速下降,因此也不是很常用.
5. Innodb使用的是哪種隔離級(jí)別呢?
InnoDB默認(rèn)使用的是可重復(fù)讀隔離級(jí)別.
6. 對(duì)MySQL的鎖了解嗎?
當(dāng)數(shù)據(jù)庫(kù)有并發(fā)事務(wù)的時(shí)候,可能會(huì)產(chǎn)生數(shù)據(jù)的不一致,這時(shí)候需要一些機(jī)制來(lái)保證訪問(wèn)的次序,鎖機(jī)制就是這樣的一個(gè)機(jī)制.
就像酒店的房間,如果大家隨意進(jìn)出,就會(huì)出現(xiàn)多人搶奪同一個(gè)房間的情況,而在房間上裝上鎖,申請(qǐng)到鑰匙的人才可以入住并且將房間鎖起來(lái),其他人只有等他使用完畢才可以再次使用.
7. MySQL都有哪些鎖呢?像上面那樣子進(jìn)行鎖定豈不是有點(diǎn)阻礙并發(fā)效率了?
從鎖的類別上來(lái)講,有共享鎖和排他鎖.
共享鎖: 又叫做讀鎖. 當(dāng)用戶要進(jìn)行數(shù)據(jù)的讀取時(shí),對(duì)數(shù)據(jù)加上共享鎖.共享鎖可以同時(shí)加上多個(gè).
排他鎖: 又叫做寫(xiě)鎖. 當(dāng)用戶要進(jìn)行數(shù)據(jù)的寫(xiě)入時(shí),對(duì)數(shù)據(jù)加上排他鎖.排他鎖只可以加一個(gè),他和其他的排他鎖,共享鎖都相斥.
用上面的例子來(lái)說(shuō)就是用戶的行為有兩種,一種是來(lái)看房,多個(gè)用戶一起看房是可以接受的. 一種是真正的入住一晚,在這期間,無(wú)論是想入住的還是想看房的都不可以.
鎖的粒度取決于具體的存儲(chǔ)引擎,InnoDB實(shí)現(xiàn)了行級(jí)鎖,頁(yè)級(jí)鎖,表級(jí)鎖.
他們的加鎖開(kāi)銷從大大小,并發(fā)能力也是從大到小.
表結(jié)構(gòu)設(shè)計(jì)
1. 為什么要盡量設(shè)定一個(gè)主鍵?
主鍵是數(shù)據(jù)庫(kù)確保數(shù)據(jù)行在整張表唯一性的保障,即使業(yè)務(wù)上本張表沒(méi)有主鍵,也建議添加一個(gè)自增長(zhǎng)的ID列作為主鍵.設(shè)定了主鍵之后,在后續(xù)的刪改查的時(shí)候可能更加快速以及確保操作數(shù)據(jù)范圍安全.
2. 主鍵使用自增ID還是UUID?
推薦使用自增ID,不要使用UUID.
因?yàn)樵贗nnoDB存儲(chǔ)引擎中,主鍵索引是作為聚簇索引存在的,也就是說(shuō),主鍵索引的B+樹(shù)葉子節(jié)點(diǎn)上存儲(chǔ)了主鍵索引以及全部的數(shù)據(jù)(按照順序),如果主鍵索引是自增ID,那么只需要不斷向后排列即可,如果是UUID,由于到來(lái)的ID與原來(lái)的大小不確定,會(huì)造成非常多的數(shù)據(jù)插入,數(shù)據(jù)移動(dòng),然后導(dǎo)致產(chǎn)生很多的內(nèi)存碎片,進(jìn)而造成插入性能的下降.
總之,在數(shù)據(jù)量大一些的情況下,用自增主鍵性能會(huì)好一些.
圖片來(lái)源于《高性能MySQL》: 其中默認(rèn)后綴為使用自增ID,_uuid
為使用UUID為主鍵的測(cè)試,測(cè)試了插入100w行和300w行的性能.

關(guān)于主鍵是聚簇索引,如果沒(méi)有主鍵,InnoDB會(huì)選擇一個(gè)唯一鍵來(lái)作為聚簇索引,如果沒(méi)有唯一鍵,會(huì)生成一個(gè)隱式的主鍵.

3. 字段為什么要求定義為not null?
MySQL官網(wǎng)這樣介紹:

null值會(huì)占用更多的字節(jié),且會(huì)在程序中造成很多與預(yù)期不符的情況.
4. 如果要存儲(chǔ)用戶的密碼散列,應(yīng)該使用什么字段進(jìn)行存儲(chǔ)?
密碼散列,鹽,用戶身份證號(hào)等固定長(zhǎng)度的字符串應(yīng)該使用char而不是varchar來(lái)存儲(chǔ),這樣可以節(jié)省空間且提高檢索效率.
存儲(chǔ)引擎相關(guān)
1. MySQL支持哪些存儲(chǔ)引擎?
MySQL支持多種存儲(chǔ)引擎,比如InnoDB,MyISAM,Memory,Archive等等.在大多數(shù)的情況下,直接選擇使用InnoDB引擎都是最合適的,InnoDB也是MySQL的默認(rèn)存儲(chǔ)引擎.
InnoDB和MyISAM有什么區(qū)別?
InnoDB支持事物,而MyISAM不支持事物
InnoDB支持行級(jí)鎖,而MyISAM支持表級(jí)鎖
InnoDB支持MVCC, 而MyISAM不支持
InnoDB支持外鍵,而MyISAM不支持
InnoDB不支持全文索引,而MyISAM支持。
零散問(wèn)題
1. MySQL中的varchar和char有什么區(qū)別.
char是一個(gè)定長(zhǎng)字段,假如申請(qǐng)了char(10)
的空間,那么無(wú)論實(shí)際存儲(chǔ)多少內(nèi)容.該字段都占用10個(gè)字符,而varchar是變長(zhǎng)的,也就是說(shuō)申請(qǐng)的只是最大長(zhǎng)度,占用的空間為實(shí)際字符長(zhǎng)度+1,最后一個(gè)字符存儲(chǔ)使用了多長(zhǎng)的空間.
在檢索效率上來(lái)講,char > varchar,因此在使用中,如果確定某個(gè)字段的值的長(zhǎng)度,可以使用char,否則應(yīng)該盡量使用varchar.例如存儲(chǔ)用戶MD5加密后的密碼,則應(yīng)該使用char.
2. varchar(10)和int(10)代表什么含義?
varchar的10代表了申請(qǐng)的空間長(zhǎng)度,也是可以存儲(chǔ)的數(shù)據(jù)的最大長(zhǎng)度,而int的10只是代表了展示的長(zhǎng)度,不足10位以0填充.也就是說(shuō),int(1)和int(10)所能存儲(chǔ)的數(shù)字大小以及占用的空間都是相同的,只是在展示時(shí)按照長(zhǎng)度展示.
3. MySQL的binlog有有幾種錄入格式?分別有什么區(qū)別?
有三種格式,statement,row和mixed.
statement模式下,記錄單元為語(yǔ)句.即每一個(gè)sql造成的影響會(huì)記錄.由于sql的執(zhí)行是有上下文的,因此在保存的時(shí)候需要保存相關(guān)的信息,同時(shí)還有一些使用了函數(shù)之類的語(yǔ)句無(wú)法被記錄復(fù)制.
row級(jí)別下,記錄單元為每一行的改動(dòng),基本是可以全部記下來(lái)但是由于很多操作,會(huì)導(dǎo)致大量行的改動(dòng)(比如alter table),因此這種模式的文件保存的信息太多,日志量太大.
mixed. 一種折中的方案,普通操作使用statement記錄,當(dāng)無(wú)法使用statement的時(shí)候使用row.
此外,新版的MySQL中對(duì)row級(jí)別也做了一些優(yōu)化,當(dāng)表結(jié)構(gòu)發(fā)生變化的時(shí)候,會(huì)記錄語(yǔ)句而不是逐行記錄.
4. 超大分頁(yè)怎么處理?
超大的分頁(yè)一般從兩個(gè)方向上來(lái)解決.
數(shù)據(jù)庫(kù)層面,這也是我們主要集中關(guān)注的(雖然收效沒(méi)那么大),類似于
select * from table where age > 20 limit 1000000,10
這種查詢其實(shí)也是有可以優(yōu)化的余地的. 這條語(yǔ)句需要load1000000數(shù)據(jù)然后基本上全部丟棄,只取10條當(dāng)然比較慢. 當(dāng)時(shí)我們可以修改為select * from table where id in (select id from table where age > 20 limit 1000000,10)
.這樣雖然也load了一百萬(wàn)的數(shù)據(jù),但是由于索引覆蓋,要查詢的所有字段都在索引中,所以速度會(huì)很快. 同時(shí)如果ID連續(xù)的好,我們還可以select * from table where id > 1000000 limit 10
,效率也是不錯(cuò)的,優(yōu)化的可能性有許多種,但是核心思想都一樣,就是減少load的數(shù)據(jù).從需求的角度減少這種請(qǐng)求....主要是不做類似的需求(直接跳轉(zhuǎn)到幾百萬(wàn)頁(yè)之后的具體某一頁(yè).只允許逐頁(yè)查看或者按照給定的路線走,這樣可預(yù)測(cè),可緩存)以及防止ID泄漏且連續(xù)被人惡意攻擊.
解決超大分頁(yè),其實(shí)主要是靠緩存,可預(yù)測(cè)性的提前查到內(nèi)容,緩存至redis等k-V數(shù)據(jù)庫(kù)中,直接返回即可.
在阿里巴巴《Java開(kāi)發(fā)手冊(cè)》中,對(duì)超大分頁(yè)的解決辦法是類似于上面提到的第一種.

5. 關(guān)心過(guò)業(yè)務(wù)系統(tǒng)里面的sql耗時(shí)嗎?統(tǒng)計(jì)過(guò)慢查詢嗎?對(duì)慢查詢都怎么優(yōu)化過(guò)?
在業(yè)務(wù)系統(tǒng)中,除了使用主鍵進(jìn)行的查詢,其他的我都會(huì)在測(cè)試庫(kù)上測(cè)試其耗時(shí),慢查詢的統(tǒng)計(jì)主要由運(yùn)維在做,會(huì)定期將業(yè)務(wù)中的慢查詢反饋給我們.
慢查詢的優(yōu)化首先要搞明白慢的原因是什么? 是查詢條件沒(méi)有命中索引?是load了不需要的數(shù)據(jù)列?還是數(shù)據(jù)量太大?
所以優(yōu)化也是針對(duì)這三個(gè)方向來(lái)的,
首先分析語(yǔ)句,看看是否load了額外的數(shù)據(jù),可能是查詢了多余的行并且拋棄掉了,可能是加載了許多結(jié)果中并不需要的列,對(duì)語(yǔ)句進(jìn)行分析以及重寫(xiě).
分析語(yǔ)句的執(zhí)行計(jì)劃,然后獲得其使用索引的情況,之后修改語(yǔ)句或者修改索引,使得語(yǔ)句可以盡可能的命中索引.
如果對(duì)語(yǔ)句的優(yōu)化已經(jīng)無(wú)法進(jìn)行,可以考慮表中的數(shù)據(jù)量是否太大,如果是的話可以進(jìn)行橫向或者縱向的分表.
6. 上面提到橫向分表和縱向分表,可以分別舉一個(gè)適合他們的例子嗎?
橫向分表是按行分表.假設(shè)我們有一張用戶表,主鍵是自增ID且同時(shí)是用戶的ID.數(shù)據(jù)量較大,有1億多條,那么此時(shí)放在一張表里的查詢效果就不太理想.我們可以根據(jù)主鍵ID進(jìn)行分表,無(wú)論是按尾號(hào)分,或者按ID的區(qū)間分都是可以的. 假設(shè)按照尾號(hào)0-99分為100個(gè)表,那么每張表中的數(shù)據(jù)就僅有100w.這時(shí)的查詢效率無(wú)疑是可以滿足要求的.
縱向分表是按列分表.假設(shè)我們現(xiàn)在有一張文章表.包含字段id-摘要-內(nèi)容
.而系統(tǒng)中的展示形式是刷新出一個(gè)列表,列表中僅包含標(biāo)題和摘要,當(dāng)用戶點(diǎn)擊某篇文章進(jìn)入詳情時(shí)才需要正文內(nèi)容.此時(shí),如果數(shù)據(jù)量大,將內(nèi)容這個(gè)很大且不經(jīng)常使用的列放在一起會(huì)拖慢原表的查詢速度.我們可以將上面的表分為兩張.id-摘要
,id-內(nèi)容
.當(dāng)用戶點(diǎn)擊詳情,那主鍵再來(lái)取一次內(nèi)容即可.而增加的存儲(chǔ)量只是很小的主鍵字段.代價(jià)很小.
當(dāng)然,分表其實(shí)和業(yè)務(wù)的關(guān)聯(lián)度很高,在分表之前一定要做好調(diào)研以及benchmark.不要按照自己的猜想盲目操作.
7. 什么是存儲(chǔ)過(guò)程?有哪些優(yōu)缺點(diǎn)?
存儲(chǔ)過(guò)程是一些預(yù)編譯的SQL語(yǔ)句。1、更加直白的理解:存儲(chǔ)過(guò)程可以說(shuō)是一個(gè)記錄集,它是由一些T-SQL語(yǔ)句組成的代碼塊,這些T-SQL語(yǔ)句代碼像一個(gè)方法一樣實(shí)現(xiàn)一些功能(對(duì)單表或多表的增刪改查),然后再給這個(gè)代碼塊取一個(gè)名字,在用到這個(gè)功能的時(shí)候調(diào)用他就行了。2、存儲(chǔ)過(guò)程是一個(gè)預(yù)編譯的代碼塊,執(zhí)行效率比較高,一個(gè)存儲(chǔ)過(guò)程替代大量T_SQL語(yǔ)句 ,可以降低網(wǎng)絡(luò)通信量,提高通信速率,可以一定程度上確保數(shù)據(jù)安全
但是,在互聯(lián)網(wǎng)項(xiàng)目中,其實(shí)是不太推薦存儲(chǔ)過(guò)程的,比較出名的就是阿里的《Java開(kāi)發(fā)手冊(cè)》中禁止使用存儲(chǔ)過(guò)程,我個(gè)人的理解是,在互聯(lián)網(wǎng)項(xiàng)目中,迭代太快,項(xiàng)目的生命周期也比較短,人員流動(dòng)相比于傳統(tǒng)的項(xiàng)目也更加頻繁,在這樣的情況下,存儲(chǔ)過(guò)程的管理確實(shí)是沒(méi)有那么方便,同時(shí),復(fù)用性也沒(méi)有寫(xiě)在服務(wù)層那么好.
8. 說(shuō)一說(shuō)三個(gè)范式
第一范式: 每個(gè)列都不可以再拆分.第二范式: 非主鍵列完全依賴于主鍵,而不能是依賴于主鍵的一部分.第三范式: 非主鍵列只依賴于主鍵,不依賴于其他非主鍵.
在設(shè)計(jì)數(shù)據(jù)庫(kù)結(jié)構(gòu)的時(shí)候,要盡量遵守三范式,如果不遵守,必須有足夠的理由.比如性能. 事實(shí)上我們經(jīng)常會(huì)為了性能而妥協(xié)數(shù)據(jù)庫(kù)的設(shè)計(jì).
9. MyBatis中的#和$有什么區(qū)別?
亂入了一個(gè)奇怪的問(wèn)題.....我只是想單獨(dú)記錄一下這個(gè)問(wèn)題,因?yàn)槌霈F(xiàn)頻率太高了.
# 會(huì)將傳入的內(nèi)容當(dāng)做字符串,而$會(huì)直接將傳入值拼接在sql語(yǔ)句中.
所以#可以在一定程度上預(yù)防sql注入攻擊.
作者:呼延十
來(lái)源:https://juejin.im/post/6844903894351347719