數(shù)據(jù)存儲(chǔ)和消息隊(duì)列
數(shù)據(jù)庫
1. MySQL 索引使用的注意事項(xiàng)
- 索引不會(huì)包含有Null值的列
只要列中包含有null值都將不會(huì)被包含在索引中。符合索引中只要有一列含有null值,那么這一列對(duì)于此符合索引就是無效的。 - 使用短索引
對(duì)串列進(jìn)行索引,如果可能應(yīng)該指定一個(gè)前綴長(zhǎng)度。例如有一個(gè)char(255)的列,如果在前10或20個(gè)字符內(nèi),多數(shù)值是惟一的,就不要對(duì)整個(gè)列進(jìn)行索引。短索引不僅可以提高查詢速度而且可以節(jié)省磁盤空間和I/O操作。 - 索引列排序
MySQL查詢只使用一個(gè)索引。因此如果where子句中已經(jīng)使用了索引的話,那么order by中的列是不會(huì)使用索引的。因此數(shù)據(jù)庫默認(rèn)排序可以符合要求的情況下不要使用排序操作,盡量不要包含多個(gè)列的排序,如果需要最好給這些列創(chuàng)建復(fù)合索引。 - like語句操作
一般情況下不鼓勵(lì)使用like操作。如果非使用不可,盡量避免%aaa%,因?yàn)椴粫?huì)使用索引,而like"aaa%"則會(huì)使用索引。 - 不要在列上進(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'
- 不使用Not IN,<>,!=操作,但<,<=,=,>,>=,between,in是可以使用索引的
- 索引要建立在經(jīng)常進(jìn)行select操作的字段上
- 索引要建立在值比較唯一的字段上。
- 對(duì)于那些定義為text,image和bit數(shù)據(jù)類型的列不應(yīng)該增加索引。因?yàn)檫@些列的數(shù)據(jù)量要么相當(dāng)大,要么取值很少。
- 在where和join中出現(xiàn)的類需要建立索引
- where的查詢條件里有不等號(hào)(where column != ...),mysql將無法使用索引
- 在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)限的語句。
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ù)讀和幻讀問題。
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)化之道
- 使用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表空間,因而速度要快很多。 - 活用commit
PL/SQL塊中,經(jīng)常將幾個(gè)互相聯(lián)系的DML語句卸載BEGIN...END,如果不影響事務(wù)的完整性,則建議在每個(gè)END前面寫一個(gè)commit,以達(dá)到對(duì)DML的即使提交和釋放事務(wù)所占資源的目的。 - where子句書寫
oracle優(yōu)化器的原理是采用自下而上的順序解析where子句,因此表之間的連接永遠(yuǎn)寫在where后面的第一個(gè)位置,并對(duì)過濾條件進(jìn)行估算,可過濾掉最大數(shù)量紀(jì)錄的條件必須寫在where子句的末尾。 - 取別名
聯(lián)合表的查詢中,表名和列名以一個(gè)字母為別名可以提高1.5倍查詢速度 - 充分利用索引
如果檢索全表,不必建索引。因?yàn)樗饕龝?huì)帶來額外的IO操作,如果檢索的數(shù)據(jù)記錄數(shù)占全部表記錄的10%以下,可以考慮建索引。
表之間的關(guān)聯(lián)字段可以考慮建索引。
如果表的記錄數(shù)較少時(shí),不建議使用索引,如數(shù)據(jù)不超過一萬行的表不要建立索引。 - 不要有超過五個(gè)以上的表連接(JOIN)
連接的表越多,其編譯的時(shí)間和連接的開銷也越大,性能越不好控制。最好把連接拆開成較小的幾個(gè)部分逐個(gè)順序執(zhí)行。優(yōu)先執(zhí)行那些能夠大量減少結(jié)果的連接。 - 盡量避免使用select *
返回的結(jié)果越大,意味著相應(yīng)的SQL語句的logical reads就越大,對(duì)服務(wù)器的性能影響就越甚。 - 使用存儲(chǔ)過程
可以考慮使用存儲(chǔ)過程封裝那些復(fù)雜的sql語句或邏輯。存儲(chǔ)過程的執(zhí)行計(jì)劃可以被緩存在內(nèi)存中較長(zhǎng)時(shí)間,減少了重新編譯的時(shí)間,而且減少了客戶端和服務(wù)器的繁復(fù)交互。 - 注意一些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)致放棄使用索引。 - 盡量避免使用游標(biāo)
游標(biāo)效率較差,如果游標(biāo)啊哦做的數(shù)據(jù)超過一萬行,那么就應(yīng)該考慮改寫。 - 盡量避免濫用distinct和order by。跟union一樣,它們?cè)黾恿祟~外的開銷,使查詢變慢。
- 盡量少使用視圖
視圖效率很低,對(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)致不走索引的還有其他的可能性:
- 使用了Oracle的move操作,此操作將導(dǎo)致索引失效
- 對(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)化法:
- 子查詢優(yōu)化法
先找出第一條數(shù)據(jù),然后大于等于這條數(shù)據(jù)的id就是要獲取的數(shù)據(jù)。但數(shù)據(jù)必須是連續(xù)的,也就是不能有where條件,where會(huì)篩選數(shù)據(jù)導(dǎo)致數(shù)據(jù)失去連續(xù)性。 - 倒排表優(yōu)化法
類似建立索引,用一張表來維護(hù)頁數(shù),然后通過高效的連接來獲得數(shù)據(jù)。但只合適數(shù)據(jù)數(shù)固定的情況,數(shù)據(jù)不能刪除,維護(hù)頁表非常困難。 - 反向查找優(yōu)化法
當(dāng)偏移量超過一半記錄數(shù)的時(shí)候,先用排序,這樣便宜就反轉(zhuǎn)了。但對(duì)于order by的優(yōu)化相當(dāng)麻煩,要增加索引,而且必須要知道總記錄數(shù)因?yàn)橐谄拼笥跀?shù)據(jù)總數(shù)一半時(shí)反轉(zhuǎn)。 - limit限制優(yōu)化法
把limit偏移量限制低于某個(gè)數(shù),超過則不予查詢。相當(dāng)暴力的手段,但聽說阿里的dba是這么干的。。。 - 只查索引法
優(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ù)庫物理層:
- 數(shù)據(jù)庫系統(tǒng)軟件應(yīng)該盡量跟數(shù)據(jù)文件分置不同存儲(chǔ)設(shè)備
- 如果可能,數(shù)據(jù)庫臨時(shí)空間,log盡量使用快速存儲(chǔ)設(shè)備。
- 數(shù)據(jù)文件應(yīng)該根據(jù)具體應(yīng)用需要分置于不同存儲(chǔ)設(shè)備來提高讀取效率
- 數(shù)據(jù)文件使用RAID。RAID5無敵!
數(shù)據(jù)庫邏輯層:
- 為數(shù)據(jù)庫的system表空間,user表空間,應(yīng)用表弓箭分離。如果可能,三類表空間應(yīng)該分在不同的物理存儲(chǔ)上。
- 應(yīng)用表空間中表的表空間,索引的表空間也應(yīng)該分離
- 創(chuàng)建表時(shí)應(yīng)考慮表所存儲(chǔ)數(shù)據(jù)的業(yè)務(wù)特性在創(chuàng)建時(shí)定義不同的起始空間和空間增長(zhǎng)方案,以盡量讓一條記錄處于一個(gè)連續(xù)的物理存儲(chǔ)空間來提高讀取效率。
- 制定不同的備份恢復(fù)和碎片整理機(jī)制
- 索引并不是越多越好,數(shù)據(jù)變化頻繁的表還應(yīng)該建立索引定期重建機(jī)制,否則索引不但不會(huì)改善性能還會(huì)降低性能。
數(shù)據(jù)應(yīng)用層:
- modeling必須要合理,數(shù)據(jù)庫建模是重中之重。一個(gè)良好設(shè)計(jì)的數(shù)據(jù)庫天生就具有優(yōu)勢(shì),而一個(gè)設(shè)計(jì)不合理的數(shù)據(jù)庫再怎么優(yōu)化也是難以解決問題的。
- sql語句優(yōu)化。這點(diǎn)太大了,比如查詢盡量使用索引,盡量避免全表掃描,慎用子查詢和Union all,奪標(biāo)join時(shí)盡量用小表去join大表。