數(shù)據(jù)庫

數(shù)據(jù)存儲(chǔ)和消息隊(duì)列

數(shù)據(jù)庫

1. MySQL 索引使用的注意事項(xiàng)

  1. 索引不會(huì)包含有Null值的列
    只要列中包含有null值都將不會(huì)被包含在索引中。符合索引中只要有一列含有null值,那么這一列對(duì)于此符合索引就是無效的。
  2. 使用短索引
    對(duì)串列進(jìn)行索引,如果可能應(yīng)該指定一個(gè)前綴長(zhǎng)度。例如有一個(gè)char(255)的列,如果在前10或20個(gè)字符內(nèi),多數(shù)值是惟一的,就不要對(duì)整個(gè)列進(jìn)行索引。短索引不僅可以提高查詢速度而且可以節(jié)省磁盤空間和I/O操作。
  3. 索引列排序
    MySQL查詢只使用一個(gè)索引。因此如果where子句中已經(jīng)使用了索引的話,那么order by中的列是不會(huì)使用索引的。因此數(shù)據(jù)庫默認(rèn)排序可以符合要求的情況下不要使用排序操作,盡量不要包含多個(gè)列的排序,如果需要最好給這些列創(chuàng)建復(fù)合索引。
  4. like語句操作
    一般情況下不鼓勵(lì)使用like操作。如果非使用不可,盡量避免%aaa%,因?yàn)椴粫?huì)使用索引,而like"aaa%"則會(huì)使用索引。
  5. 不要在列上進(jìn)行運(yùn)算
select * from users where YEAR(adddate)<2007

將在每個(gè)行上進(jìn)行運(yùn)算,這將導(dǎo)致索引失效而進(jìn)行全表掃描。可以改為

select * from users where adddate<'2007-01-01'
  1. 不使用Not IN,<>,!=操作,但<,<=,=,>,>=,between,in是可以使用索引的
  2. 索引要建立在經(jīng)常進(jìn)行select操作的字段上
  3. 索引要建立在值比較唯一的字段上。
  4. 對(duì)于那些定義為text,image和bit數(shù)據(jù)類型的列不應(yīng)該增加索引。因?yàn)檫@些列的數(shù)據(jù)量要么相當(dāng)大,要么取值很少。
  5. 在where和join中出現(xiàn)的類需要建立索引
  6. where的查詢條件里有不等號(hào)(where column != ...),mysql將無法使用索引
  7. 在join操作時(shí),MySQL只有在主鍵和外鍵的數(shù)據(jù)類型相同時(shí)才能使用索引,否則即使建立了索引也不會(huì)使用。

參考:
《mysql索引使用技巧及注意事項(xiàng)》
《MySQL索引類型總結(jié)和使用技巧以及注意事項(xiàng)》

2. DDL、DML、DCL分別指什么

  • 數(shù)據(jù)庫操縱語言DML data mamipulation language:
    select, update, insert, delete。
    用于對(duì)數(shù)據(jù)庫的數(shù)據(jù)進(jìn)行一些操作
  • 數(shù)據(jù)庫定義語言DDL Data Define Language:
    create, alter, drop等。
    DDL主要用在定義或改變表的結(jié)構(gòu),數(shù)據(jù)類型,表之間的鏈接和約束等初始化工作上。
  • 數(shù)據(jù)庫控制語言DCL Data Control Language:
    grant, deny, revoke等。
    用來設(shè)置或更改數(shù)據(jù)庫用戶或角色權(quán)限的語句。

參考:
《淺談 DML、DDL、DCL的區(qū)別》

3. explain命令

MySQL的explain命令用于SQL語句的查詢執(zhí)行計(jì)劃QEP。這條命令的數(shù)據(jù)結(jié)果能夠讓我們了解到MySQL優(yōu)化器是如何執(zhí)行SQL語句的。
這條命令并沒有提供任何調(diào)整建議,但它能夠提供重要的信息來幫助做出調(diào)優(yōu)決策。

MySQL的explain語法可以運(yùn)行在select語句或者特定表上。如果作用在表上,那么此命令等同于dedsc表命令。使用在select語句上時(shí),只需要在SQL語句開始前加上explain。

參考:
《MySQL EXPLAIN 命令詳解學(xué)習(xí)

4. left join,right join,inner join

4.1 內(nèi)連接inner join
內(nèi)連接使用比較運(yùn)算符根據(jù)每個(gè)表公有的列的值匹配兩個(gè)表中的行。

4.2 左外鏈接left join
左外鏈接的結(jié)果集包括子句中指定的左表的所有行,而不僅僅是連接列所匹配的行。如果左表的某行在右表中沒有匹配行,則結(jié)果集中國(guó)此行右表的所有選擇列表均為空值。

4.3 右外鏈接right join
右外連接是左外連接的反向鏈接,將返回右表的所有行,沒有匹配數(shù)據(jù)時(shí)處理方式與左外連接相同。

5. 數(shù)據(jù)庫事物ACID(原子性、一致性、隔離性、持久性)

  • 原子性:
    事務(wù)不可分割,組成事務(wù)的各個(gè)邏輯單元不可分割
  • 一致性:
    事務(wù)執(zhí)行的前后,數(shù)據(jù)完整性保持一致
  • 隔離性:
    事務(wù)執(zhí)行不應(yīng)該受到其他事務(wù)的干擾
  • 持久性:
    事務(wù)一旦結(jié)束,數(shù)據(jù)就持久化到數(shù)據(jù)庫中

6. 事物的隔離級(jí)別(讀未提交、讀以提交、可重復(fù)讀、可序列化讀)

6.1 Read Uncommitted讀未提交
一個(gè)事務(wù)可以讀取另一個(gè)未提交事務(wù)的數(shù)據(jù)。此隔離級(jí)別不能解決臟讀,不可重復(fù)讀和幻讀問題。

6.2 Read Committed讀提交
一個(gè)事務(wù)要等另一個(gè)事務(wù)提交后才能讀取數(shù)據(jù)。若有事務(wù)對(duì)數(shù)據(jù)進(jìn)行update操作時(shí),讀操作事務(wù)要等待這個(gè)更新操作事務(wù)提交后才能讀取數(shù)據(jù),,可以解決臟讀,但無法解決不可重復(fù)讀和幻讀。
大多數(shù)據(jù)庫默認(rèn)為此隔離級(jí)別,如SQL Server和Oracle。

6.3 Repeatable Read重復(fù)讀
開始讀取數(shù)據(jù)(事務(wù)開啟)時(shí),不允許修改update操作。重復(fù)讀可以解決臟讀和不可重復(fù)讀問題,但無法解決幻讀問題。
MySQL數(shù)據(jù)庫默認(rèn)為此隔離級(jí)別。

6.4 Serializable序列化
序列化是最高的事務(wù)隔離級(jí)別。在該級(jí)別下,事務(wù)串行化順序執(zhí)行,此級(jí)別以鎖表的方式使得其他的線程只能在鎖外等待,所以效率最為低下,非常消耗數(shù)據(jù)庫性能。序列化可以解決臟讀,不可重復(fù)讀和幻讀問題。

參考:
《理解事務(wù)的4種隔離級(jí)別》

7. 臟讀、幻讀、不可重復(fù)讀

7.1 臟讀
臟讀是指在一個(gè)事務(wù)處理過程里讀取了另一個(gè)未提交的事務(wù)中的數(shù)據(jù)。
當(dāng)一個(gè)事務(wù)正在多次修改一個(gè)數(shù)據(jù),而在這個(gè)事務(wù)中這多次的修改都還未提交,這時(shí)如果一個(gè)并發(fā)的事務(wù)來訪問該數(shù)據(jù),就會(huì)造成兩個(gè)事務(wù)得到的數(shù)據(jù)不一致。

7.2 不可重復(fù)讀
不可重復(fù)讀是指在對(duì)于數(shù)據(jù)庫中的某個(gè)數(shù)據(jù),一個(gè)事務(wù)范圍內(nèi)多次查詢卻反悔了不同的數(shù)據(jù)值。這時(shí)由于查詢間隔,被另一個(gè)事務(wù)修改并提交了。
不可重復(fù)讀和臟讀的區(qū)別是,臟讀是某一事務(wù)讀取了另一個(gè)事務(wù)未提交的臟數(shù)據(jù),而不可重復(fù)讀則是讀取了前一事務(wù)提交的數(shù)據(jù)。

7.3 幻讀(虛讀)
幻讀是事務(wù)非獨(dú)立執(zhí)行時(shí)發(fā)生的一種現(xiàn)象。讀取的是另一個(gè)事務(wù)insert的數(shù)據(jù)?;米x的重點(diǎn)在于新增或者刪除(數(shù)據(jù)條數(shù)發(fā)生變化)
例如第一個(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ā)生了幻覺一樣.
幻讀和不可重復(fù)讀都是讀取了另一條已經(jīng)提交的事務(wù)(臟讀是讀取未提交的事務(wù)),所不同的是不可重復(fù)讀查詢的都是同一個(gè)數(shù)據(jù)項(xiàng),而幻讀針對(duì)的是一批數(shù)據(jù)整體。

參考:
《數(shù)據(jù)庫事務(wù)的四大特性以及事務(wù)的隔離級(jí)別》
《對(duì)于臟讀,不可重復(fù)讀,幻讀的一點(diǎn)理解,看懂紅字很關(guān)鍵》

8. 數(shù)據(jù)庫的幾大范式

8.1 第一范式1NF
數(shù)據(jù)庫表的每一列都是不可分割的基本數(shù)據(jù)項(xiàng)。例如電話號(hào)碼這個(gè)屬性可以被繼續(xù)分割為辦公電話,手機(jī)號(hào)碼等屬性,在第一范式的語義下不應(yīng)該作為單獨(dú)的一列出現(xiàn)。
在任何一個(gè)關(guān)系數(shù)據(jù)庫中,第一范式是對(duì)關(guān)系模式的基本要求,不滿足第一范式的數(shù)據(jù)庫就不是關(guān)系數(shù)據(jù)庫。

8.2 第二范式2NF
在滿足第一范式的情況下,數(shù)據(jù)庫表中的每一行必須是可以被唯一地區(qū)分,即每一行中有一個(gè)唯一表示將這行與其他行區(qū)分出來。這個(gè)唯一標(biāo)示就是主鍵。
2NF的語義下,所有非主鍵的字段都要依賴主鍵。第二范式就是一個(gè)有唯一主鍵在表中保證每一行都是唯一的,存在一個(gè)列被定義為唯一主鍵的表就是第二范式。

8.3 第三范式3NF
在滿足第一第二范式的前提下,非主鍵字段斗魚主鍵字段有直接依賴關(guān)系,不存在傳遞依賴。即非主鍵字段只依賴主鍵字段,而不依賴其他的非主鍵字段。
第三范式就是父子兩張表,在子表中的外鍵是父表的主鍵,子表中的外鍵值必須是父表中的主鍵值。

8.4 鮑依斯-科得范式BCNF
在第三范式的基礎(chǔ)上,數(shù)據(jù)庫表中如果不存在任何字段對(duì)任一候選關(guān)鍵字段的傳遞函數(shù)依賴則符合第三范式。

8.5 第四范式4NF
第四范式用于處理復(fù)雜的復(fù)合主鍵所導(dǎo)致的問題。第四范式用來識(shí)別那些需要花費(fèi)為多個(gè)不同的實(shí)體。
第四范式就是在一個(gè)沒有段獨(dú)立列被定義為唯一主鍵的表中用多個(gè)列組合一起被定義為唯一主鍵。用復(fù)合列做主鍵的表就是第四范式。

參考:
《數(shù)據(jù)庫的四個(gè)范式之間的區(qū)別》
《對(duì)關(guān)系型數(shù)據(jù)庫五個(gè)范式的理解》
《[學(xué)習(xí)筆記]數(shù)據(jù)庫設(shè)計(jì)三大范式與BCNF,學(xué)習(xí)筆記》

9. 數(shù)據(jù)庫常見的命令

由于篇幅所限,這里只給出相關(guān)鏈接。

參考:
《mysql數(shù)據(jù)庫常用命令》
《數(shù)據(jù)庫常用命令概括》

10. 說說分庫與分表設(shè)計(jì)

當(dāng)單表數(shù)據(jù)量達(dá)到一定規(guī)模,比如千萬級(jí)別(對(duì)于MySQL而言當(dāng)數(shù)據(jù)量超過200萬是就會(huì)有很嚴(yán)重的查詢速度限制了),此時(shí)做很多操作都會(huì)相當(dāng)費(fèi)時(shí)費(fèi)力,所以可以考慮進(jìn)行分表處理。

數(shù)據(jù)的切分Sharding根據(jù)其切分規(guī)則的類型,可以分為兩種切分模式:一種是按照不同的表或者schema來切分到不同的數(shù)據(jù)庫之上,這種切割稱為垂直切分;另一種則是根據(jù)表中的數(shù)據(jù)的邏輯關(guān)系將同一個(gè)表中的數(shù)據(jù)按照條件拆分到多態(tài)數(shù)據(jù)庫上面,稱為水平切分。

分表常用方式:

  • 使用時(shí)間作為依據(jù)分庫/分表
  • 是用數(shù)字作為分庫/分表的標(biāo)準(zhǔn)
  • 使用MD5區(qū)分

垂直切分(業(yè)務(wù)切分)

  • 拆分后俄舞清晰,拆分規(guī)則明確
  • 系統(tǒng)之間整合或擴(kuò)展容易
  • 數(shù)據(jù)維護(hù)簡(jiǎn)單
  • 部分業(yè)務(wù)表無法join,只能通過接口方式解決,提高了系統(tǒng)復(fù)雜度。
  • 受每種業(yè)務(wù)不同的限制存在單褲性能瓶頸,不易數(shù)據(jù)擴(kuò)展跟性能提高。
  • 事務(wù)處理復(fù)雜。

垂直切分是按照業(yè)務(wù)的分類將表分散到不同的庫,所以有些業(yè)務(wù)表會(huì)過于龐大,存在單庫讀寫與存儲(chǔ)瓶頸,所以就需要水平拆分來做解決。

水平切分
相較于垂直拆分,水平拆分不是將表做分類,而是按照某個(gè)字段的某種規(guī)則來分散到多個(gè)庫之中。誒個(gè)表中包含一部分?jǐn)?shù)據(jù)。水平切分是按照數(shù)據(jù)行的切分,將表中的某些行切分到一個(gè)數(shù)據(jù)庫,而另外的某些行又切分到其他的數(shù)據(jù)庫中。

水平切割優(yōu)點(diǎn):

  • 拆分規(guī)則抽象好,join操作較簡(jiǎn)單
  • 不存在單庫大數(shù)據(jù),高并發(fā)的性能瓶頸。
  • 應(yīng)用端改造較少
  • 提高了系統(tǒng)的穩(wěn)定性跟負(fù)載能力

缺點(diǎn):

  • 拆分規(guī)則難以抽象
  • 分片事務(wù)一致性難以解決
  • 數(shù)據(jù)多次擴(kuò)展難度跟維護(hù)量極大
  • 跨庫join性能較差

參考:
《千萬數(shù)據(jù)的分庫分表(一)》
《分表與分庫使用場(chǎng)景以及設(shè)計(jì)方式》
《淺談分庫分表》

11. 分庫與分表帶來的分布式困境與應(yīng)對(duì)之策(如何解決分布式下的分庫分表,全局表?)

這題有點(diǎn)。。。太大神級(jí)別了,我這種菜鳥很難在短時(shí)間內(nèi)消化這類的知識(shí)博客。本著不誤人子弟的原則,由于我沒有徹底理解一些資料的說法,因此不在這里給出我的答案,只給出一些參考鏈接,如果有人能有比較好的答案,歡迎給出。

《分庫分表的幾種常見玩法及如何解決跨庫查詢等問題》
《每日學(xué)習(xí)20170224-分庫分表全局ID生成》

12. 說說 SQL 優(yōu)化之道

  1. 使用truncate代替delete
    oracle執(zhí)行delete后會(huì)將被刪除的數(shù)據(jù)存放到undo表空間以便回復(fù)。如果用戶使用rollback而不是commit,則oracle會(huì)利用undo表空間中的數(shù)據(jù)進(jìn)行恢復(fù)。而使用truncate時(shí),oracle不會(huì)將被刪除的數(shù)據(jù)放入undo表空間,因而速度要快很多。
  2. 活用commit
    PL/SQL塊中,經(jīng)常將幾個(gè)互相聯(lián)系的DML語句卸載BEGIN...END,如果不影響事務(wù)的完整性,則建議在每個(gè)END前面寫一個(gè)commit,以達(dá)到對(duì)DML的即使提交和釋放事務(wù)所占資源的目的。
  3. where子句書寫
    oracle優(yōu)化器的原理是采用自下而上的順序解析where子句,因此表之間的連接永遠(yuǎn)寫在where后面的第一個(gè)位置,并對(duì)過濾條件進(jìn)行估算,可過濾掉最大數(shù)量紀(jì)錄的條件必須寫在where子句的末尾。
  4. 取別名
    聯(lián)合表的查詢中,表名和列名以一個(gè)字母為別名可以提高1.5倍查詢速度
  5. 充分利用索引
    如果檢索全表,不必建索引。因?yàn)樗饕龝?huì)帶來額外的IO操作,如果檢索的數(shù)據(jù)記錄數(shù)占全部表記錄的10%以下,可以考慮建索引。
    表之間的關(guān)聯(lián)字段可以考慮建索引。
    如果表的記錄數(shù)較少時(shí),不建議使用索引,如數(shù)據(jù)不超過一萬行的表不要建立索引。
  6. 不要有超過五個(gè)以上的表連接(JOIN)
    連接的表越多,其編譯的時(shí)間和連接的開銷也越大,性能越不好控制。最好把連接拆開成較小的幾個(gè)部分逐個(gè)順序執(zhí)行。優(yōu)先執(zhí)行那些能夠大量減少結(jié)果的連接。
  7. 盡量避免使用select *
    返回的結(jié)果越大,意味著相應(yīng)的SQL語句的logical reads就越大,對(duì)服務(wù)器的性能影響就越甚。
  8. 使用存儲(chǔ)過程
    可以考慮使用存儲(chǔ)過程封裝那些復(fù)雜的sql語句或邏輯。存儲(chǔ)過程的執(zhí)行計(jì)劃可以被緩存在內(nèi)存中較長(zhǎng)時(shí)間,減少了重新編譯的時(shí)間,而且減少了客戶端和服務(wù)器的繁復(fù)交互。
  9. 注意一些sql語句將會(huì)使引擎放棄使用索引而進(jìn)行全盤掃描。應(yīng)盡量避免類似sql語句的使用
    !=,<>, or會(huì)導(dǎo)致引擎不走索引。
    避免在where子句中對(duì)字段進(jìn)行null值判斷,否則不走索引。
    like'%abc%'不走索引(前置百分號(hào)不走索引,后置走)
    in和not in也要慎用,否則導(dǎo)致全表掃描??梢杂胋etween代替。
    where子句中使用參數(shù)也會(huì)導(dǎo)致放棄使用索引。因?yàn)閟ql只有在運(yùn)行時(shí)才會(huì)解析局部變量,但優(yōu)化程序不能將訪問計(jì)劃的選擇推遲到運(yùn)行時(shí)。
    where子句中對(duì)字段進(jìn)行表達(dá)式或函數(shù)操作會(huì)導(dǎo)致放棄使用索引。
  10. 盡量避免使用游標(biāo)
    游標(biāo)效率較差,如果游標(biāo)啊哦做的數(shù)據(jù)超過一萬行,那么就應(yīng)該考慮改寫。
  11. 盡量避免濫用distinct和order by。跟union一樣,它們?cè)黾恿祟~外的開銷,使查詢變慢。
  12. 盡量少使用視圖
    視圖效率很低,對(duì)視圖操作比直接對(duì)表操作慢。可以使用stored procedure來代替它。特別注意不要使用視圖嵌套。視圖嵌套增加了尋找原始資料的難度。

參考:
《高級(jí)sql優(yōu)化詳解》
《sql優(yōu)化心得》
《數(shù)據(jù)庫SQL優(yōu)化大總結(jié)之 百萬級(jí)數(shù)據(jù)庫優(yōu)化方案》

13. MySQL遇到的死鎖問題、如何排查與解決

13.1 MySQL常用存儲(chǔ)引擎的鎖機(jī)制
MyISAM和MEMORY采用表級(jí)鎖table-level locking。
BDB采用頁面鎖page-level locking或表級(jí)鎖,默認(rèn)為頁面鎖。
InnoDB支持行級(jí)鎖row-level locking和表級(jí)鎖,默認(rèn)為行級(jí)鎖。

13.2 鎖特點(diǎn)
表級(jí)鎖:開銷小,加鎖快;不會(huì)出現(xiàn)死鎖。鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)度最低。
行級(jí)鎖:開銷大,加鎖慢;會(huì)出現(xiàn)死鎖。鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。
頁面鎖:開銷和加鎖時(shí)間介于表鎖和行鎖之間;會(huì)出現(xiàn)死鎖。鎖定粒度介于表鎖和行鎖之間并發(fā)度一般。

13.3 鎖的使用場(chǎng)景
表級(jí)鎖更適合以查詢?yōu)橹鳎挥猩倭堪此饕龡l件更新數(shù)據(jù)的應(yīng)用。
行級(jí)鎖更適合有大量按索引條件并發(fā)更新數(shù)據(jù),同時(shí)又有并發(fā)查詢的應(yīng)用,如一些在線事務(wù)處理系統(tǒng)。

13.4 死鎖的出現(xiàn)
在MySQL中,行級(jí)鎖并不是直接鎖記錄,而是鎖索引。索引分為朱建索引和非主鍵索引兩種。如果一條sql語句操作了主鍵索引,MySQL就會(huì)鎖定這條主鍵索引;如果一條語句操作了非主鍵索引,MySQL就會(huì)先鎖定該非主鍵索引,再鎖定相關(guān)的主鍵索引。
在update。delete操作時(shí),MySQL不僅鎖定where條件掃描過的所有索引記錄,而且會(huì)鎖定相鄰的鍵值。
用戶A查詢一條紀(jì)錄,然后修改該條紀(jì)錄;這時(shí)用戶B修改該條紀(jì)錄,這時(shí)用戶A的事務(wù)里鎖的性質(zhì)由查詢的共享鎖企圖上升到獨(dú)占鎖,而用戶B里的獨(dú)占鎖由于A 有共享鎖存在所以必須等A釋放掉共享鎖,而A由于B的獨(dú)占鎖而無法上升的獨(dú)占鎖也就不可能釋放共享鎖,于是出現(xiàn)了死鎖。這種死鎖比較隱蔽,但在稍大點(diǎn)的項(xiàng) 目中經(jīng)常發(fā)生。

13.5 死鎖的檢測(cè)與處理
MySQL有自己的死鎖檢測(cè),如果發(fā)現(xiàn)出現(xiàn)了死鎖,會(huì)自行kill掉相關(guān)線程并在status里留下一條記錄以供查詢。
排查死鎖時(shí),首先要根據(jù)死鎖日志來分析循環(huán)等待的場(chǎng)景,然后根據(jù)當(dāng)前各個(gè)事務(wù)執(zhí)行的sql分析出家鎖類型以及順序,意向推斷出如何形成循環(huán)等待,以期找到死鎖產(chǎn)生的原因。
MySQL的死鎖絕大部分情況都是由于不良好的代碼造成的,因此提高代碼的質(zhì)量是最根本的解決辦法。

參考:
《mysql數(shù)據(jù)庫死鎖的產(chǎn)生原因及解決辦法》
《MySQL死鎖問題分析及解決方法實(shí)例詳解》

14. 存儲(chǔ)引擎的 InnoDB與MyISAM區(qū)別,優(yōu)缺點(diǎn),使用場(chǎng)景

MyISAM管理非事務(wù)表。它提供高速存儲(chǔ)和檢索,以及全文搜索能力。MyISAM在所有MySQL配置里都被支持,它是默認(rèn)的存儲(chǔ)引擎。
InnoDB提供事務(wù)安全表。

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

14.2 存儲(chǔ)空間
MyISAM可被壓縮,存儲(chǔ)空間較小。
InnoDB的表需要更多的內(nèi)存和存儲(chǔ)。他會(huì)在主內(nèi)存中建立其專用的緩沖池用于高速緩沖數(shù)據(jù)和索引。

14.3 可移植性,備份及恢復(fù)
MyISAM的數(shù)據(jù)以文件形式存儲(chǔ),所以在跨平臺(tái)的數(shù)據(jù)轉(zhuǎn)移中會(huì)很方便。在備份和恢復(fù)時(shí)可以針對(duì)單獨(dú)某個(gè)表進(jìn)行操作。
InnoDB比較麻煩,可以選擇拷貝數(shù)據(jù)文件,備份binlog或者使用MySQLdump。但在數(shù)據(jù)量達(dá)到幾十g的情況下會(huì)相當(dāng)麻煩。

14.4 事務(wù)安全
MyISAM每次查詢具有原子性,不支持事務(wù)。
InnoDB支持事務(wù),是具有崩潰修復(fù)能力的事務(wù)安全型表。

14.5 sql語句效率
MyISAM在select語句執(zhí)行上更優(yōu)。
而InnoDB在insert,update,delete語句更優(yōu)。
如果沒有where子句的count,則是MyISAM更優(yōu),因?yàn)樗4媪吮淼木唧w行數(shù),而InnoDB需要進(jìn)行逐行統(tǒng)計(jì)掃描。

14.6 鎖
MyISAM只支持表鎖。
InnoDB支持表鎖,行鎖。但I(xiàn)nnoDB的行鎖只對(duì)where的主鍵有效,非主鍵的where都會(huì)鎖全表。

14.7 外鍵
MyISAM不支持外鍵而InnoDB支持。

總之,InnoDB的設(shè)計(jì)目標(biāo)是處理大容量數(shù)據(jù)庫系統(tǒng),他的cpu利用率是其他基于磁盤的關(guān)系數(shù)據(jù)庫引擎所不能比的。InnoDB可以應(yīng)對(duì)更為復(fù)雜的情況,特別是對(duì)并發(fā)的處理要比MyISAM高效。

參考:
《MySQL存儲(chǔ)引擎MyISAM與InnoDB的優(yōu)劣》
《MySQL存儲(chǔ)引擎InnoDB與Myisam的六大區(qū)別》

15. 索引類別(B+樹索引、全文索引、哈希索引)、索引的原理

B+樹是一個(gè)平衡的多叉樹,從根節(jié)點(diǎn)到葉子節(jié)點(diǎn)的高度差值不超過1,而且同層級(jí)的節(jié)點(diǎn)間有指針互相鏈接。
在B+樹上的常規(guī)檢索,從根節(jié)點(diǎn)到葉子結(jié)點(diǎn)的搜索效率基本相當(dāng),不會(huì)出現(xiàn)大幅波動(dòng),而且基于索引的順序掃描時(shí),也可以利用雙向指針快速左右移動(dòng),效率非常高。

哈希索引采用一定的哈希算法,把鍵值換算成新的哈希值,檢索時(shí)不需要類似B+樹那樣從根節(jié)點(diǎn)到葉子結(jié)點(diǎn)逐級(jí)查找,只需要一次哈希算法即可like定位到相應(yīng)的位置,速度非???。
哈希索引對(duì)范圍查詢檢索無效,因?yàn)榻?jīng)過哈希算法后無法保證有序性。同理,哈希索引也無法利用索引完成排序,以及l(fā)ike這樣的模糊查詢。

全文索引是目前搜索引擎使用的一種關(guān)鍵技術(shù)。其實(shí)現(xiàn)非常復(fù)雜,是通過詞來進(jìn)行檢索的。

MySQL對(duì)索引定義為:是幫助MySQL高效獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)。
在數(shù)據(jù)之外,數(shù)據(jù)庫系統(tǒng)還維護(hù)著滿足特定查找算法的數(shù)據(jù)結(jié)構(gòu)。這些數(shù)據(jù)結(jié)構(gòu)以某種方式引用(指向)數(shù)據(jù)。這樣就可以在這些數(shù)據(jù)結(jié)構(gòu)上實(shí)現(xiàn)高級(jí)查找算法。而這種數(shù)據(jù)結(jié)構(gòu)就是索引。
索引是對(duì)數(shù)據(jù)庫表中一個(gè)或多個(gè)列的值進(jìn)行排序的結(jié)構(gòu)。與在表中搜索所有的行相比,索引用指針指向存儲(chǔ)在表中指定列的數(shù)據(jù)值,然后根據(jù)指定的次序排序這些指針,有助于快速地獲取信息。

參考:
《MySQL索引背后的數(shù)據(jù)結(jié)構(gòu)及算法原理》
《MySQL B+樹索引和哈希索引的區(qū)別》

16. 什么是自適應(yīng)哈希索引(AHI)

InnoDB存儲(chǔ)引擎會(huì)監(jiān)控對(duì)表上索引的查找,如果觀察到建立哈希索引可以帶來速度的提升,則建立哈希索引,所以稱之為自適應(yīng)。
自適應(yīng)哈希索引通過緩沖池的B+樹構(gòu)造而來,因此建立的速度很快。而且不需要將整個(gè)表都建立哈希索引,InnoDB會(huì)自動(dòng)根據(jù)訪問的頻率和模式來為某些頁建立哈希索引。
自適應(yīng)哈希索引由MySQL自動(dòng)管理,無法人為干預(yù),但可以通過參數(shù)innodb_adaptive_hash_index來禁用或啟動(dòng)此特性,默認(rèn)是開啟

參考:
《MySQL中自適應(yīng)哈希索引》
《MySql 自適應(yīng)哈希索引》

17. 為什么要用 B+tree作為MySQL索引的數(shù)據(jù)結(jié)構(gòu)

二叉查找樹的變種紅黑樹也可以用于實(shí)現(xiàn)索引,但文件系統(tǒng)及數(shù)據(jù)庫系統(tǒng)普遍采用B+樹作為索引結(jié)構(gòu)。
一般來說,索引本身也很大,不可能全部存儲(chǔ)在內(nèi)存中,因此索引往往以索引文件的形式存儲(chǔ)在磁盤上。這樣的話,索引查找過程中就要產(chǎn)生磁盤I/O消耗,相對(duì)于內(nèi)存的存取,I/O的存取消耗是及其大的。
所以,評(píng)價(jià)一個(gè)數(shù)據(jù)結(jié)構(gòu)作為索引的優(yōu)劣最重要的指標(biāo)就是在查找過程中磁盤I/O操作次數(shù)的漸進(jìn)復(fù)雜度。也就是說,索引的結(jié)構(gòu)組織要盡量減少查找過程中磁盤I/O的存取次數(shù)。
數(shù)據(jù)庫系統(tǒng)利用了磁盤的預(yù)讀原理,將一個(gè)節(jié)點(diǎn)的大小設(shè)為等于一個(gè)頁,這樣每個(gè)節(jié)點(diǎn)只需要一次I/O就可以完全載入。每次新建節(jié)點(diǎn)時(shí),直接申請(qǐng)一個(gè)頁的空間,這樣就保證一個(gè)節(jié)點(diǎn)物理上也存儲(chǔ)在一個(gè)頁里,加之計(jì)算機(jī)存儲(chǔ)分配都是按頁對(duì)其的,就實(shí)現(xiàn)了一個(gè)node只需一次I/O。
而紅黑樹這種結(jié)構(gòu),邏輯上很近的節(jié)點(diǎn)物理上可能很遠(yuǎn),無法利用局部性,所以紅黑樹的效率比B+樹要差很多。

參考:
《數(shù)據(jù)庫為什么要用B+樹結(jié)構(gòu)--MySQL索引結(jié)構(gòu)的實(shí)現(xiàn)》

18. 聚集索引與非聚集索引的區(qū)別

聚集索引:數(shù)據(jù)行的物理順序與列值(一般是主鍵列)的邏輯順序相同,一個(gè)表中只能擁有一個(gè)聚集索引。

非聚集索引:該索引中索引的邏輯順序與磁盤上的物理存儲(chǔ)順序不同,一個(gè)表中可以擁有多個(gè)非聚集索引。

參考:
《聚集索引與非聚集索引的總結(jié)》
《【數(shù)據(jù)庫SQL】——聚集索引和非聚集索引根本區(qū)別以及使用方式》

19. 遇到過索引失效的情況沒,什么時(shí)候可能會(huì)出現(xiàn),如何解決

除過某些sql語句是會(huì)不走索引的,導(dǎo)致不走索引的還有其他的可能性:

  1. 使用了Oracle的move操作,此操作將導(dǎo)致索引失效
  2. 對(duì)分區(qū)表進(jìn)行了刪除,添加,合并,分割等操作將有可能導(dǎo)致Oracle數(shù)據(jù)庫的索引失效。

這些Oracle索引失效的原因基本都是因?yàn)閞owid改變了,從而導(dǎo)致了索引失效。因此建議在執(zhí)行相應(yīng)sql語句后附加update indexes子句來使Oracle自動(dòng)維護(hù)全局索引以防失效。

20. limit 20000 加載很慢怎么解決

當(dāng)一個(gè)數(shù)據(jù)庫表過于龐大,Limit offset,length中的offset過大會(huì)導(dǎo)致查詢語句非常緩慢,因?yàn)橐獟呙璧臄?shù)據(jù)太過于龐大。

limit分頁優(yōu)化法:

  1. 子查詢優(yōu)化法
    先找出第一條數(shù)據(jù),然后大于等于這條數(shù)據(jù)的id就是要獲取的數(shù)據(jù)。但數(shù)據(jù)必須是連續(xù)的,也就是不能有where條件,where會(huì)篩選數(shù)據(jù)導(dǎo)致數(shù)據(jù)失去連續(xù)性。
  2. 倒排表優(yōu)化法
    類似建立索引,用一張表來維護(hù)頁數(shù),然后通過高效的連接來獲得數(shù)據(jù)。但只合適數(shù)據(jù)數(shù)固定的情況,數(shù)據(jù)不能刪除,維護(hù)頁表非常困難。
  3. 反向查找優(yōu)化法
    當(dāng)偏移量超過一半記錄數(shù)的時(shí)候,先用排序,這樣便宜就反轉(zhuǎn)了。但對(duì)于order by的優(yōu)化相當(dāng)麻煩,要增加索引,而且必須要知道總記錄數(shù)因?yàn)橐谄拼笥跀?shù)據(jù)總數(shù)一半時(shí)反轉(zhuǎn)。
  4. limit限制優(yōu)化法
    把limit偏移量限制低于某個(gè)數(shù),超過則不予查詢。相當(dāng)暴力的手段,但聽說阿里的dba是這么干的。。。
  5. 只查索引法
    優(yōu)化后的子查詢只讀索引。

參考:
《MYSQL分頁limit速度太慢的優(yōu)化方法》
《mysql優(yōu)化limit查詢語句的5個(gè)方法》

21. 如何選擇合適的分布式主鍵方案

在只使用單數(shù)據(jù)庫時(shí),自增主鍵是一個(gè)相當(dāng)廣泛的選擇。但當(dāng)使用分布式的集群架構(gòu)時(shí),對(duì)大表進(jìn)行水平分表,就不能使用自增id,因?yàn)閕nsert的記錄插到哪個(gè)分表依分表規(guī)則判定決定。如果是自增id,則各個(gè)分表中id就會(huì)重復(fù),導(dǎo)致查詢,刪除時(shí)出現(xiàn)異常。而如果只是集群的分布式架構(gòu)而沒有采用水平分表,則可以考慮使用自增id來作為主鍵。但也會(huì)存在主鍵全局唯一性地問題。

那么另一種使用普遍的主鍵,uuid,也不適合作為某些數(shù)據(jù)庫的主鍵。例如InnoDB這種聚集主鍵類型的引擎,數(shù)據(jù)按照主鍵進(jìn)行排序。而UUID的無序性讓InnoDB產(chǎn)生巨大的IO壓力,因此不適合作為物理主鍵,但可以作為邏輯主鍵。

也可以使用GUID來作為主鍵。GUID維護(hù)簡(jiǎn)單,實(shí)現(xiàn)容易。但計(jì)算成本很大,且GUID長(zhǎng)度過大,浪費(fèi)存儲(chǔ)空間。

通過集群標(biāo)號(hào)加集群內(nèi)的自增兩個(gè)字段共同組成唯一的主鍵。實(shí)現(xiàn)與維護(hù)簡(jiǎn)單,對(duì)應(yīng)用透明。

對(duì)于分布式系統(tǒng)來說,全局唯一性至關(guān)重要,主鍵必須是唯一的,以防引起異常。其次關(guān)注性能問題,存儲(chǔ)占用不能過大,主鍵的獲取不能過于復(fù)雜否則影響插入效率。

參考:
《分布式環(huán)境下數(shù)據(jù)庫主鍵方案》

22. 選擇合適的數(shù)據(jù)存儲(chǔ)方案

此題有歧義,不知道問的是數(shù)據(jù)存儲(chǔ)設(shè)備的選擇還是數(shù)據(jù)庫的選擇。在這里以數(shù)據(jù)庫的選擇進(jìn)行解答。

22.1 關(guān)系型數(shù)據(jù)庫MySQL
MySQL是一個(gè)最流行的開源關(guān)系型數(shù)據(jù)庫。通常情況下MySQL數(shù)據(jù)庫是第一選擇方案。

22.2 內(nèi)存數(shù)據(jù)庫Redis
隨著數(shù)據(jù)量增長(zhǎng),MySQL已經(jīng)無法滿足大型互聯(lián)網(wǎng)類應(yīng)用的需求。因此,Redis基于內(nèi)存存儲(chǔ)數(shù)據(jù),可以極大的提高查詢性能,對(duì)產(chǎn)品在架構(gòu)上時(shí)很好的補(bǔ)充。Redis是典型的以空間換時(shí)間的策略,使用更多的內(nèi)存換取CPU資源,通過增加系統(tǒng)的內(nèi)存消耗,來加快程序的運(yùn)行速度。

22.3 文檔數(shù)據(jù)庫MongoDB
MongoDB是對(duì)傳統(tǒng)關(guān)系型數(shù)據(jù)庫的補(bǔ)充,非常適合高伸縮性的場(chǎng)景,是可擴(kuò)展性的表結(jié)構(gòu)。MongoDB適合存儲(chǔ)大尺寸的數(shù)據(jù)和海量的日志數(shù)據(jù)。它利用分片集群支持海量數(shù)據(jù),同時(shí)使用聚集分析和MapReduce的能力。

22.4 非關(guān)系型數(shù)據(jù)庫NoSQL
非關(guān)系型數(shù)據(jù)庫以鍵值對(duì)存儲(chǔ),它的結(jié)構(gòu)不固定,每一個(gè)元組可以有不一樣的字段。每個(gè)元組可以根據(jù)需要增加一些自己的鍵值對(duì),這樣就不會(huì)局限于固定的結(jié)構(gòu),可以減少一些時(shí)間和空間的開銷。所有非關(guān)系型數(shù)據(jù)庫都是NoSQL數(shù)據(jù)庫。
(這里的NoSQL略有重復(fù),因?yàn)镸ongoDB,redis,hbase都是NoSQL數(shù)據(jù)庫)

22.5 列數(shù)據(jù)庫HBase
HBase適合海量數(shù)據(jù)的存儲(chǔ)和高性能實(shí)時(shí)查詢,它運(yùn)行于HDFS文件系統(tǒng)之上,并且作為MapReduce分布式處理的目標(biāo)數(shù)據(jù)庫,以支撐離線分析型應(yīng)用。

參考:
《服務(wù)端指南 數(shù)據(jù)存儲(chǔ)篇 | 選擇合適的數(shù)據(jù)存儲(chǔ)方案》

23. 常見的幾種分布式ID的設(shè)計(jì)方案

23.1 UUID
UUID保證了唯一性,只能有計(jì)算機(jī)生成,不需要遠(yuǎn)程調(diào)用,時(shí)延低,性能高;但UUID過長(zhǎng),不適合做索引字段而且無序,對(duì)于部分?jǐn)?shù)據(jù)庫引擎不友好。

23.2.采用自增機(jī)制+其他字段來保證唯一性自增ID
此機(jī)制確保id唯一性,而且充分接住了數(shù)據(jù)庫的自增ID機(jī)制,可靠性高,生成了有序的ID。但相當(dāng)依賴于數(shù)據(jù)庫,且對(duì)于附加字段的選取需要一定的技術(shù)。

23.3 類snowflake方案
生成一個(gè)64位數(shù)字,該數(shù)據(jù)被劃分為多個(gè)段,分別表示時(shí)間戳,機(jī)器編碼,序號(hào)。
它時(shí)間戳在高位,自增序列在低位,整個(gè)ID是趨勢(shì)遞增的,按照時(shí)間有序,且高性能,可以根據(jù)業(yè)務(wù)需求靈活調(diào)整區(qū)段劃分。但其依賴于及其時(shí)鐘,而且過長(zhǎng),且由于涉及到分布式環(huán)境,每臺(tái)及其上的時(shí)鐘不可能完全同步,可能會(huì)出現(xiàn)不是全局遞增的情況。

除此之外還有很多的id設(shè)計(jì)方案,可以參考附加的鏈接。在這里由于篇幅就不予詳細(xì)講解了。

參考:
《分布式ID方案有哪些以及各自的優(yōu)劣勢(shì),我們當(dāng)如何選擇》
《分布式系統(tǒng)唯一ID生成方案匯總》

24. 常見的數(shù)據(jù)庫優(yōu)化方案,在你的項(xiàng)目中數(shù)據(jù)庫如何進(jìn)行優(yōu)化的

這個(gè)問題請(qǐng)甩給DBA,如果沒有DBA。。。

數(shù)據(jù)庫物理層:

  1. 數(shù)據(jù)庫系統(tǒng)軟件應(yīng)該盡量跟數(shù)據(jù)文件分置不同存儲(chǔ)設(shè)備
  2. 如果可能,數(shù)據(jù)庫臨時(shí)空間,log盡量使用快速存儲(chǔ)設(shè)備。
  3. 數(shù)據(jù)文件應(yīng)該根據(jù)具體應(yīng)用需要分置于不同存儲(chǔ)設(shè)備來提高讀取效率
  4. 數(shù)據(jù)文件使用RAID。RAID5無敵!

數(shù)據(jù)庫邏輯層:

  1. 為數(shù)據(jù)庫的system表空間,user表空間,應(yīng)用表弓箭分離。如果可能,三類表空間應(yīng)該分在不同的物理存儲(chǔ)上。
  2. 應(yīng)用表空間中表的表空間,索引的表空間也應(yīng)該分離
  3. 創(chuàng)建表時(shí)應(yīng)考慮表所存儲(chǔ)數(shù)據(jù)的業(yè)務(wù)特性在創(chuàng)建時(shí)定義不同的起始空間和空間增長(zhǎng)方案,以盡量讓一條記錄處于一個(gè)連續(xù)的物理存儲(chǔ)空間來提高讀取效率。
  4. 制定不同的備份恢復(fù)和碎片整理機(jī)制
  5. 索引并不是越多越好,數(shù)據(jù)變化頻繁的表還應(yīng)該建立索引定期重建機(jī)制,否則索引不但不會(huì)改善性能還會(huì)降低性能。

數(shù)據(jù)應(yīng)用層:

  1. modeling必須要合理,數(shù)據(jù)庫建模是重中之重。一個(gè)良好設(shè)計(jì)的數(shù)據(jù)庫天生就具有優(yōu)勢(shì),而一個(gè)設(shè)計(jì)不合理的數(shù)據(jù)庫再怎么優(yōu)化也是難以解決問題的。
  2. sql語句優(yōu)化。這點(diǎn)太大了,比如查詢盡量使用索引,盡量避免全表掃描,慎用子查詢和Union all,奪標(biāo)join時(shí)盡量用小表去join大表。

參考:
《有哪些常見的數(shù)據(jù)庫優(yōu)化方法?》

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 轉(zhuǎn) # https://www.cnblogs.com/easypass/archive/2010/12/ 08/...
    呂品?閱讀 10,107評(píng)論 0 44
  • 數(shù)據(jù)庫的基本是概念名詞解釋: 數(shù)據(jù)庫名詞解釋 元組:可以理解為表的每一行就是一個(gè)元組 候選碼:若關(guān)系中的某一屬性組...
    杰倫哎呦哎呦閱讀 1,228評(píng)論 0 6
  • 本問很多內(nèi)容摘錄和參考自下面的文章,感謝他們的共享: 面經(jīng)整理-Java基礎(chǔ) https://blog.csdn....
    terry蔣閱讀 1,291評(píng)論 0 6
  • 面試題5:union all 和 union的區(qū)別 Union:對(duì)兩個(gè)結(jié)果集進(jìn)行并集操作,不包括重復(fù)行,同時(shí)進(jìn)行默...
    行者和他的鋼筆閱讀 1,042評(píng)論 0 1
  • 過去的終將過去 未來才真正屬于你 即使過去再傷痕累累 也要勇敢的重新起步 充實(shí) 完善自己 讓自己變得更加優(yōu)秀 而不...
    忍冬sherry閱讀 153評(píng)論 0 1

友情鏈接更多精彩內(nèi)容