數據存儲和消息隊列
數據庫
1. MySQL 索引使用的注意事項
- 索引不會包含有Null值的列
只要列中包含有null值都將不會被包含在索引中。符合索引中只要有一列含有null值,那么這一列對于此符合索引就是無效的。 - 使用短索引
對串列進行索引,如果可能應該指定一個前綴長度。例如有一個char(255)的列,如果在前10或20個字符內,多數值是惟一的,就不要對整個列進行索引。短索引不僅可以提高查詢速度而且可以節(jié)省磁盤空間和I/O操作。 - 索引列排序
MySQL查詢只使用一個索引。因此如果where子句中已經使用了索引的話,那么order by中的列是不會使用索引的。因此數據庫默認排序可以符合要求的情況下不要使用排序操作,盡量不要包含多個列的排序,如果需要最好給這些列創(chuàng)建復合索引。 - like語句操作
一般情況下不鼓勵使用like操作。如果非使用不可,盡量避免%aaa%,因為不會使用索引,而like"aaa%"則會使用索引。 - 不要在列上進行運算
select * from users where YEAR(adddate)<2007
將在每個行上進行運算,這將導致索引失效而進行全表掃描??梢愿臑?/p>
select * from users where adddate<'2007-01-01'
- 不使用Not IN,<>,!=操作,但<,<=,=,>,>=,between,in是可以使用索引的
- 索引要建立在經常進行select操作的字段上
- 索引要建立在值比較唯一的字段上。
- 對于那些定義為text,image和bit數據類型的列不應該增加索引。因為這些列的數據量要么相當大,要么取值很少。
- 在where和join中出現的類需要建立索引
- where的查詢條件里有不等號(where column != ...),mysql將無法使用索引
- 在join操作時,MySQL只有在主鍵和外鍵的數據類型相同時才能使用索引,否則即使建立了索引也不會使用。
參考:
《mysql索引使用技巧及注意事項》
《MySQL索引類型總結和使用技巧以及注意事項》
2. DDL、DML、DCL分別指什么
- 數據庫操縱語言DML data mamipulation language:
select, update, insert, delete。
用于對數據庫的數據進行一些操作 - 數據庫定義語言DDL Data Define Language:
create, alter, drop等。
DDL主要用在定義或改變表的結構,數據類型,表之間的鏈接和約束等初始化工作上。 - 數據庫控制語言DCL Data Control Language:
grant, deny, revoke等。
用來設置或更改數據庫用戶或角色權限的語句。
3. explain命令
MySQL的explain命令用于SQL語句的查詢執(zhí)行計劃QEP。這條命令的數據結果能夠讓我們了解到MySQL優(yōu)化器是如何執(zhí)行SQL語句的。
這條命令并沒有提供任何調整建議,但它能夠提供重要的信息來幫助做出調優(yōu)決策。
MySQL的explain語法可以運行在select語句或者特定表上。如果作用在表上,那么此命令等同于dedsc表命令。使用在select語句上時,只需要在SQL語句開始前加上explain。
4. left join,right join,inner join
4.1 內連接inner join
內連接使用比較運算符根據每個表公有的列的值匹配兩個表中的行。
4.2 左外鏈接left join
左外鏈接的結果集包括子句中指定的左表的所有行,而不僅僅是連接列所匹配的行。如果左表的某行在右表中沒有匹配行,則結果集中國此行右表的所有選擇列表均為空值。
4.3 右外鏈接right join
右外連接是左外連接的反向鏈接,將返回右表的所有行,沒有匹配數據時處理方式與左外連接相同。
5. 數據庫事物ACID(原子性、一致性、隔離性、持久性)
- 原子性:
事務不可分割,組成事務的各個邏輯單元不可分割 - 一致性:
事務執(zhí)行的前后,數據完整性保持一致 - 隔離性:
事務執(zhí)行不應該受到其他事務的干擾 - 持久性:
事務一旦結束,數據就持久化到數據庫中
6. 事物的隔離級別(讀未提交、讀以提交、可重復讀、可序列化讀)
6.1 Read Uncommitted讀未提交
一個事務可以讀取另一個未提交事務的數據。此隔離級別不能解決臟讀,不可重復讀和幻讀問題。
6.2 Read Committed讀提交
一個事務要等另一個事務提交后才能讀取數據。若有事務對數據進行update操作時,讀操作事務要等待這個更新操作事務提交后才能讀取數據,,可以解決臟讀,但無法解決不可重復讀和幻讀。
大多數據庫默認為此隔離級別,如SQL Server和Oracle。
6.3 Repeatable Read重復讀
開始讀取數據(事務開啟)時,不允許修改update操作。重復讀可以解決臟讀和不可重復讀問題,但無法解決幻讀問題。
MySQL數據庫默認為此隔離級別。
6.4 Serializable序列化
序列化是最高的事務隔離級別。在該級別下,事務串行化順序執(zhí)行,此級別以鎖表的方式使得其他的線程只能在鎖外等待,所以效率最為低下,非常消耗數據庫性能。序列化可以解決臟讀,不可重復讀和幻讀問題。
參考:
《理解事務的4種隔離級別》
7. 臟讀、幻讀、不可重復讀
7.1 臟讀
臟讀是指在一個事務處理過程里讀取了另一個未提交的事務中的數據。
當一個事務正在多次修改一個數據,而在這個事務中這多次的修改都還未提交,這時如果一個并發(fā)的事務來訪問該數據,就會造成兩個事務得到的數據不一致。
7.2 不可重復讀
不可重復讀是指在對于數據庫中的某個數據,一個事務范圍內多次查詢卻反悔了不同的數據值。這時由于查詢間隔,被另一個事務修改并提交了。
不可重復讀和臟讀的區(qū)別是,臟讀是某一事務讀取了另一個事務未提交的臟數據,而不可重復讀則是讀取了前一事務提交的數據。
7.3 幻讀(虛讀)
幻讀是事務非獨立執(zhí)行時發(fā)生的一種現象。讀取的是另一個事務insert的數據。幻讀的重點在于新增或者刪除(數據條數發(fā)生變化)
例如第一個事務對一個表中的數據進行了修改,比如這種修改涉及到表中的“全部數據行”。同時,第二個事務也修改這個表中的數據,這種修改是向表中插入“一行新數據”。那么,以后就會發(fā)生操作第一個事務的用戶發(fā)現表中還存在沒有修改的數據行,就好象發(fā)生了幻覺一樣.
幻讀和不可重復讀都是讀取了另一條已經提交的事務(臟讀是讀取未提交的事務),所不同的是不可重復讀查詢的都是同一個數據項,而幻讀針對的是一批數據整體。
參考:
《數據庫事務的四大特性以及事務的隔離級別》
《對于臟讀,不可重復讀,幻讀的一點理解,看懂紅字很關鍵》
8. 數據庫的幾大范式
8.1 第一范式1NF
數據庫表的每一列都是不可分割的基本數據項。例如電話號碼這個屬性可以被繼續(xù)分割為辦公電話,手機號碼等屬性,在第一范式的語義下不應該作為單獨的一列出現。
在任何一個關系數據庫中,第一范式是對關系模式的基本要求,不滿足第一范式的數據庫就不是關系數據庫。
8.2 第二范式2NF
在滿足第一范式的情況下,數據庫表中的每一行必須是可以被唯一地區(qū)分,即每一行中有一個唯一表示將這行與其他行區(qū)分出來。這個唯一標示就是主鍵。
2NF的語義下,所有非主鍵的字段都要依賴主鍵。第二范式就是一個有唯一主鍵在表中保證每一行都是唯一的,存在一個列被定義為唯一主鍵的表就是第二范式。
8.3 第三范式3NF
在滿足第一第二范式的前提下,非主鍵字段斗魚主鍵字段有直接依賴關系,不存在傳遞依賴。即非主鍵字段只依賴主鍵字段,而不依賴其他的非主鍵字段。
第三范式就是父子兩張表,在子表中的外鍵是父表的主鍵,子表中的外鍵值必須是父表中的主鍵值。
8.4 鮑依斯-科得范式BCNF
在第三范式的基礎上,數據庫表中如果不存在任何字段對任一候選關鍵字段的傳遞函數依賴則符合第三范式。
8.5 第四范式4NF
第四范式用于處理復雜的復合主鍵所導致的問題。第四范式用來識別那些需要花費為多個不同的實體。
第四范式就是在一個沒有段獨立列被定義為唯一主鍵的表中用多個列組合一起被定義為唯一主鍵。用復合列做主鍵的表就是第四范式。
參考:
《數據庫的四個范式之間的區(qū)別》
《對關系型數據庫五個范式的理解》
《[學習筆記]數據庫設計三大范式與BCNF,學習筆記》
9. 數據庫常見的命令
由于篇幅所限,這里只給出相關鏈接。
參考:
《mysql數據庫常用命令》
《數據庫常用命令概括》
10. 說說分庫與分表設計
當單表數據量達到一定規(guī)模,比如千萬級別(對于MySQL而言當數據量超過200萬是就會有很嚴重的查詢速度限制了),此時做很多操作都會相當費時費力,所以可以考慮進行分表處理。
數據的切分Sharding根據其切分規(guī)則的類型,可以分為兩種切分模式:一種是按照不同的表或者schema來切分到不同的數據庫之上,這種切割稱為垂直切分;另一種則是根據表中的數據的邏輯關系將同一個表中的數據按照條件拆分到多態(tài)數據庫上面,稱為水平切分。
分表常用方式:
- 使用時間作為依據分庫/分表
- 是用數字作為分庫/分表的標準
- 使用MD5區(qū)分
垂直切分(業(yè)務切分)
- 拆分后俄舞清晰,拆分規(guī)則明確
- 系統(tǒng)之間整合或擴展容易
- 數據維護簡單
- 部分業(yè)務表無法join,只能通過接口方式解決,提高了系統(tǒng)復雜度。
- 受每種業(yè)務不同的限制存在單褲性能瓶頸,不易數據擴展跟性能提高。
- 事務處理復雜。
垂直切分是按照業(yè)務的分類將表分散到不同的庫,所以有些業(yè)務表會過于龐大,存在單庫讀寫與存儲瓶頸,所以就需要水平拆分來做解決。
水平切分
相較于垂直拆分,水平拆分不是將表做分類,而是按照某個字段的某種規(guī)則來分散到多個庫之中。誒個表中包含一部分數據。水平切分是按照數據行的切分,將表中的某些行切分到一個數據庫,而另外的某些行又切分到其他的數據庫中。
水平切割優(yōu)點:
- 拆分規(guī)則抽象好,join操作較簡單
- 不存在單庫大數據,高并發(fā)的性能瓶頸。
- 應用端改造較少
- 提高了系統(tǒng)的穩(wěn)定性跟負載能力
缺點:
- 拆分規(guī)則難以抽象
- 分片事務一致性難以解決
- 數據多次擴展難度跟維護量極大
- 跨庫join性能較差
參考:
《千萬數據的分庫分表(一)》
《分表與分庫使用場景以及設計方式》
《淺談分庫分表》
11. 分庫與分表帶來的分布式困境與應對之策(如何解決分布式下的分庫分表,全局表?)
這題有點。。。太大神級別了,我這種菜鳥很難在短時間內消化這類的知識博客。本著不誤人子弟的原則,由于我沒有徹底理解一些資料的說法,因此不在這里給出我的答案,只給出一些參考鏈接,如果有人能有比較好的答案,歡迎給出。
《分庫分表的幾種常見玩法及如何解決跨庫查詢等問題》
《每日學習20170224-分庫分表全局ID生成》
12. 說說 SQL 優(yōu)化之道
- 使用truncate代替delete
oracle執(zhí)行delete后會將被刪除的數據存放到undo表空間以便回復。如果用戶使用rollback而不是commit,則oracle會利用undo表空間中的數據進行恢復。而使用truncate時,oracle不會將被刪除的數據放入undo表空間,因而速度要快很多。 - 活用commit
PL/SQL塊中,經常將幾個互相聯系的DML語句卸載BEGIN...END,如果不影響事務的完整性,則建議在每個END前面寫一個commit,以達到對DML的即使提交和釋放事務所占資源的目的。 - where子句書寫
oracle優(yōu)化器的原理是采用自下而上的順序解析where子句,因此表之間的連接永遠寫在where后面的第一個位置,并對過濾條件進行估算,可過濾掉最大數量紀錄的條件必須寫在where子句的末尾。 - 取別名
聯合表的查詢中,表名和列名以一個字母為別名可以提高1.5倍查詢速度 - 充分利用索引
如果檢索全表,不必建索引。因為索引會帶來額外的IO操作,如果檢索的數據記錄數占全部表記錄的10%以下,可以考慮建索引。
表之間的關聯字段可以考慮建索引。
如果表的記錄數較少時,不建議使用索引,如數據不超過一萬行的表不要建立索引。 - 不要有超過五個以上的表連接(JOIN)
連接的表越多,其編譯的時間和連接的開銷也越大,性能越不好控制。最好把連接拆開成較小的幾個部分逐個順序執(zhí)行。優(yōu)先執(zhí)行那些能夠大量減少結果的連接。 - 盡量避免使用select *
返回的結果越大,意味著相應的SQL語句的logical reads就越大,對服務器的性能影響就越甚。 - 使用存儲過程
可以考慮使用存儲過程封裝那些復雜的sql語句或邏輯。存儲過程的執(zhí)行計劃可以被緩存在內存中較長時間,減少了重新編譯的時間,而且減少了客戶端和服務器的繁復交互。 - 注意一些sql語句將會使引擎放棄使用索引而進行全盤掃描。應盡量避免類似sql語句的使用
!=,<>, or會導致引擎不走索引。
避免在where子句中對字段進行null值判斷,否則不走索引。
like'%abc%'不走索引(前置百分號不走索引,后置走)
in和not in也要慎用,否則導致全表掃描??梢杂胋etween代替。
where子句中使用參數也會導致放棄使用索引。因為sql只有在運行時才會解析局部變量,但優(yōu)化程序不能將訪問計劃的選擇推遲到運行時。
where子句中對字段進行表達式或函數操作會導致放棄使用索引。 - 盡量避免使用游標
游標效率較差,如果游標啊哦做的數據超過一萬行,那么就應該考慮改寫。 - 盡量避免濫用distinct和order by。跟union一樣,它們增加了額外的開銷,使查詢變慢。
- 盡量少使用視圖
視圖效率很低,對視圖操作比直接對表操作慢。可以使用stored procedure來代替它。特別注意不要使用視圖嵌套。視圖嵌套增加了尋找原始資料的難度。
參考:
《高級sql優(yōu)化詳解》
《sql優(yōu)化心得》
《數據庫SQL優(yōu)化大總結之 百萬級數據庫優(yōu)化方案》
13. MySQL遇到的死鎖問題、如何排查與解決
13.1 MySQL常用存儲引擎的鎖機制
MyISAM和MEMORY采用表級鎖table-level locking。
BDB采用頁面鎖page-level locking或表級鎖,默認為頁面鎖。
InnoDB支持行級鎖row-level locking和表級鎖,默認為行級鎖。
13.2 鎖特點
表級鎖:開銷小,加鎖快;不會出現死鎖。鎖定粒度大,發(fā)生鎖沖突的概率最高,并發(fā)度最低。
行級鎖:開銷大,加鎖慢;會出現死鎖。鎖定粒度最小,發(fā)生鎖沖突的概率最低,并發(fā)度也最高。
頁面鎖:開銷和加鎖時間介于表鎖和行鎖之間;會出現死鎖。鎖定粒度介于表鎖和行鎖之間并發(fā)度一般。
13.3 鎖的使用場景
表級鎖更適合以查詢?yōu)橹?,只有少量按索引條件更新數據的應用。
行級鎖更適合有大量按索引條件并發(fā)更新數據,同時又有并發(fā)查詢的應用,如一些在線事務處理系統(tǒng)。
13.4 死鎖的出現
在MySQL中,行級鎖并不是直接鎖記錄,而是鎖索引。索引分為朱建索引和非主鍵索引兩種。如果一條sql語句操作了主鍵索引,MySQL就會鎖定這條主鍵索引;如果一條語句操作了非主鍵索引,MySQL就會先鎖定該非主鍵索引,再鎖定相關的主鍵索引。
在update。delete操作時,MySQL不僅鎖定where條件掃描過的所有索引記錄,而且會鎖定相鄰的鍵值。
用戶A查詢一條紀錄,然后修改該條紀錄;這時用戶B修改該條紀錄,這時用戶A的事務里鎖的性質由查詢的共享鎖企圖上升到獨占鎖,而用戶B里的獨占鎖由于A 有共享鎖存在所以必須等A釋放掉共享鎖,而A由于B的獨占鎖而無法上升的獨占鎖也就不可能釋放共享鎖,于是出現了死鎖。這種死鎖比較隱蔽,但在稍大點的項 目中經常發(fā)生。
13.5 死鎖的檢測與處理
MySQL有自己的死鎖檢測,如果發(fā)現出現了死鎖,會自行kill掉相關線程并在status里留下一條記錄以供查詢。
排查死鎖時,首先要根據死鎖日志來分析循環(huán)等待的場景,然后根據當前各個事務執(zhí)行的sql分析出家鎖類型以及順序,意向推斷出如何形成循環(huán)等待,以期找到死鎖產生的原因。
MySQL的死鎖絕大部分情況都是由于不良好的代碼造成的,因此提高代碼的質量是最根本的解決辦法。
參考:
《mysql數據庫死鎖的產生原因及解決辦法》
《MySQL死鎖問題分析及解決方法實例詳解》
14. 存儲引擎的 InnoDB與MyISAM區(qū)別,優(yōu)缺點,使用場景
MyISAM管理非事務表。它提供高速存儲和檢索,以及全文搜索能力。MyISAM在所有MySQL配置里都被支持,它是默認的存儲引擎。
InnoDB提供事務安全表。
14.1 存儲結構:
每個MyISAM在磁盤上存儲成三個文件,第一個文件的名字以表的名字開始,擴展名支出文件類型。.frm文件存儲表的定義。數據文件的擴展名為.MYD,索引文件的擴展名是.MYI。
InnoDB所有的表都保存在同一個數據文件中(也有可能是多個文件,或者是獨立的表空間文件),InnoDB表的大小只受限于操作系統(tǒng)的大小,一般為2GB。
14.2 存儲空間
MyISAM可被壓縮,存儲空間較小。
InnoDB的表需要更多的內存和存儲。他會在主內存中建立其專用的緩沖池用于高速緩沖數據和索引。
14.3 可移植性,備份及恢復
MyISAM的數據以文件形式存儲,所以在跨平臺的數據轉移中會很方便。在備份和恢復時可以針對單獨某個表進行操作。
InnoDB比較麻煩,可以選擇拷貝數據文件,備份binlog或者使用MySQLdump。但在數據量達到幾十g的情況下會相當麻煩。
14.4 事務安全
MyISAM每次查詢具有原子性,不支持事務。
InnoDB支持事務,是具有崩潰修復能力的事務安全型表。
14.5 sql語句效率
MyISAM在select語句執(zhí)行上更優(yōu)。
而InnoDB在insert,update,delete語句更優(yōu)。
如果沒有where子句的count,則是MyISAM更優(yōu),因為它保存了表的具體行數,而InnoDB需要進行逐行統(tǒng)計掃描。
14.6 鎖
MyISAM只支持表鎖。
InnoDB支持表鎖,行鎖。但InnoDB的行鎖只對where的主鍵有效,非主鍵的where都會鎖全表。
14.7 外鍵
MyISAM不支持外鍵而InnoDB支持。
總之,InnoDB的設計目標是處理大容量數據庫系統(tǒng),他的cpu利用率是其他基于磁盤的關系數據庫引擎所不能比的。InnoDB可以應對更為復雜的情況,特別是對并發(fā)的處理要比MyISAM高效。
參考:
《MySQL存儲引擎MyISAM與InnoDB的優(yōu)劣》
《MySQL存儲引擎InnoDB與Myisam的六大區(qū)別》
15. 索引類別(B+樹索引、全文索引、哈希索引)、索引的原理
B+樹是一個平衡的多叉樹,從根節(jié)點到葉子節(jié)點的高度差值不超過1,而且同層級的節(jié)點間有指針互相鏈接。
在B+樹上的常規(guī)檢索,從根節(jié)點到葉子結點的搜索效率基本相當,不會出現大幅波動,而且基于索引的順序掃描時,也可以利用雙向指針快速左右移動,效率非常高。
哈希索引采用一定的哈希算法,把鍵值換算成新的哈希值,檢索時不需要類似B+樹那樣從根節(jié)點到葉子結點逐級查找,只需要一次哈希算法即可like定位到相應的位置,速度非???。
哈希索引對范圍查詢檢索無效,因為經過哈希算法后無法保證有序性。同理,哈希索引也無法利用索引完成排序,以及l(fā)ike這樣的模糊查詢。
全文索引是目前搜索引擎使用的一種關鍵技術。其實現非常復雜,是通過詞來進行檢索的。
MySQL對索引定義為:是幫助MySQL高效獲取數據的數據結構。
在數據之外,數據庫系統(tǒng)還維護著滿足特定查找算法的數據結構。這些數據結構以某種方式引用(指向)數據。這樣就可以在這些數據結構上實現高級查找算法。而這種數據結構就是索引。
索引是對數據庫表中一個或多個列的值進行排序的結構。與在表中搜索所有的行相比,索引用指針指向存儲在表中指定列的數據值,然后根據指定的次序排序這些指針,有助于快速地獲取信息。
參考:
《MySQL索引背后的數據結構及算法原理》
《MySQL B+樹索引和哈希索引的區(qū)別》
16. 什么是自適應哈希索引(AHI)
InnoDB存儲引擎會監(jiān)控對表上索引的查找,如果觀察到建立哈希索引可以帶來速度的提升,則建立哈希索引,所以稱之為自適應。
自適應哈希索引通過緩沖池的B+樹構造而來,因此建立的速度很快。而且不需要將整個表都建立哈希索引,InnoDB會自動根據訪問的頻率和模式來為某些頁建立哈希索引。
自適應哈希索引由MySQL自動管理,無法人為干預,但可以通過參數innodb_adaptive_hash_index來禁用或啟動此特性,默認是開啟
參考:
《MySQL中自適應哈希索引》
《MySql 自適應哈希索引》
17. 為什么要用 B+tree作為MySQL索引的數據結構
二叉查找樹的變種紅黑樹也可以用于實現索引,但文件系統(tǒng)及數據庫系統(tǒng)普遍采用B+樹作為索引結構。
一般來說,索引本身也很大,不可能全部存儲在內存中,因此索引往往以索引文件的形式存儲在磁盤上。這樣的話,索引查找過程中就要產生磁盤I/O消耗,相對于內存的存取,I/O的存取消耗是及其大的。
所以,評價一個數據結構作為索引的優(yōu)劣最重要的指標就是在查找過程中磁盤I/O操作次數的漸進復雜度。也就是說,索引的結構組織要盡量減少查找過程中磁盤I/O的存取次數。
數據庫系統(tǒng)利用了磁盤的預讀原理,將一個節(jié)點的大小設為等于一個頁,這樣每個節(jié)點只需要一次I/O就可以完全載入。每次新建節(jié)點時,直接申請一個頁的空間,這樣就保證一個節(jié)點物理上也存儲在一個頁里,加之計算機存儲分配都是按頁對其的,就實現了一個node只需一次I/O。
而紅黑樹這種結構,邏輯上很近的節(jié)點物理上可能很遠,無法利用局部性,所以紅黑樹的效率比B+樹要差很多。
參考:
《數據庫為什么要用B+樹結構--MySQL索引結構的實現》
18. 聚集索引與非聚集索引的區(qū)別
聚集索引:數據行的物理順序與列值(一般是主鍵列)的邏輯順序相同,一個表中只能擁有一個聚集索引。
非聚集索引:該索引中索引的邏輯順序與磁盤上的物理存儲順序不同,一個表中可以擁有多個非聚集索引。
參考:
《聚集索引與非聚集索引的總結》
《【數據庫SQL】——聚集索引和非聚集索引根本區(qū)別以及使用方式》
19. 遇到過索引失效的情況沒,什么時候可能會出現,如何解決
除過某些sql語句是會不走索引的,導致不走索引的還有其他的可能性:
- 使用了Oracle的move操作,此操作將導致索引失效
- 對分區(qū)表進行了刪除,添加,合并,分割等操作將有可能導致Oracle數據庫的索引失效。
這些Oracle索引失效的原因基本都是因為rowid改變了,從而導致了索引失效。因此建議在執(zhí)行相應sql語句后附加update indexes子句來使Oracle自動維護全局索引以防失效。
20. limit 20000 加載很慢怎么解決
當一個數據庫表過于龐大,Limit offset,length中的offset過大會導致查詢語句非常緩慢,因為要掃描的數據太過于龐大。
limit分頁優(yōu)化法:
- 子查詢優(yōu)化法
先找出第一條數據,然后大于等于這條數據的id就是要獲取的數據。但數據必須是連續(xù)的,也就是不能有where條件,where會篩選數據導致數據失去連續(xù)性。 - 倒排表優(yōu)化法
類似建立索引,用一張表來維護頁數,然后通過高效的連接來獲得數據。但只合適數據數固定的情況,數據不能刪除,維護頁表非常困難。 - 反向查找優(yōu)化法
當偏移量超過一半記錄數的時候,先用排序,這樣便宜就反轉了。但對于order by的優(yōu)化相當麻煩,要增加索引,而且必須要知道總記錄數因為要在偏移大于數據總數一半時反轉。 - limit限制優(yōu)化法
把limit偏移量限制低于某個數,超過則不予查詢。相當暴力的手段,但聽說阿里的dba是這么干的。。。 - 只查索引法
優(yōu)化后的子查詢只讀索引。
參考:
《MYSQL分頁limit速度太慢的優(yōu)化方法》
《mysql優(yōu)化limit查詢語句的5個方法》
21. 如何選擇合適的分布式主鍵方案
在只使用單數據庫時,自增主鍵是一個相當廣泛的選擇。但當使用分布式的集群架構時,對大表進行水平分表,就不能使用自增id,因為insert的記錄插到哪個分表依分表規(guī)則判定決定。如果是自增id,則各個分表中id就會重復,導致查詢,刪除時出現異常。而如果只是集群的分布式架構而沒有采用水平分表,則可以考慮使用自增id來作為主鍵。但也會存在主鍵全局唯一性地問題。
那么另一種使用普遍的主鍵,uuid,也不適合作為某些數據庫的主鍵。例如InnoDB這種聚集主鍵類型的引擎,數據按照主鍵進行排序。而UUID的無序性讓InnoDB產生巨大的IO壓力,因此不適合作為物理主鍵,但可以作為邏輯主鍵。
也可以使用GUID來作為主鍵。GUID維護簡單,實現容易。但計算成本很大,且GUID長度過大,浪費存儲空間。
通過集群標號加集群內的自增兩個字段共同組成唯一的主鍵。實現與維護簡單,對應用透明。
對于分布式系統(tǒng)來說,全局唯一性至關重要,主鍵必須是唯一的,以防引起異常。其次關注性能問題,存儲占用不能過大,主鍵的獲取不能過于復雜否則影響插入效率。
22. 選擇合適的數據存儲方案
此題有歧義,不知道問的是數據存儲設備的選擇還是數據庫的選擇。在這里以數據庫的選擇進行解答。
22.1 關系型數據庫MySQL
MySQL是一個最流行的開源關系型數據庫。通常情況下MySQL數據庫是第一選擇方案。
22.2 內存數據庫Redis
隨著數據量增長,MySQL已經無法滿足大型互聯網類應用的需求。因此,Redis基于內存存儲數據,可以極大的提高查詢性能,對產品在架構上時很好的補充。Redis是典型的以空間換時間的策略,使用更多的內存換取CPU資源,通過增加系統(tǒng)的內存消耗,來加快程序的運行速度。
22.3 文檔數據庫MongoDB
MongoDB是對傳統(tǒng)關系型數據庫的補充,非常適合高伸縮性的場景,是可擴展性的表結構。MongoDB適合存儲大尺寸的數據和海量的日志數據。它利用分片集群支持海量數據,同時使用聚集分析和MapReduce的能力。
22.4 非關系型數據庫NoSQL
非關系型數據庫以鍵值對存儲,它的結構不固定,每一個元組可以有不一樣的字段。每個元組可以根據需要增加一些自己的鍵值對,這樣就不會局限于固定的結構,可以減少一些時間和空間的開銷。所有非關系型數據庫都是NoSQL數據庫。
(這里的NoSQL略有重復,因為MongoDB,redis,hbase都是NoSQL數據庫)
22.5 列數據庫HBase
HBase適合海量數據的存儲和高性能實時查詢,它運行于HDFS文件系統(tǒng)之上,并且作為MapReduce分布式處理的目標數據庫,以支撐離線分析型應用。
參考:
《服務端指南 數據存儲篇 | 選擇合適的數據存儲方案》
23. 常見的幾種分布式ID的設計方案
23.1 UUID
UUID保證了唯一性,只能有計算機生成,不需要遠程調用,時延低,性能高;但UUID過長,不適合做索引字段而且無序,對于部分數據庫引擎不友好。
23.2.采用自增機制+其他字段來保證唯一性自增ID
此機制確保id唯一性,而且充分接住了數據庫的自增ID機制,可靠性高,生成了有序的ID。但相當依賴于數據庫,且對于附加字段的選取需要一定的技術。
23.3 類snowflake方案
生成一個64位數字,該數據被劃分為多個段,分別表示時間戳,機器編碼,序號。
它時間戳在高位,自增序列在低位,整個ID是趨勢遞增的,按照時間有序,且高性能,可以根據業(yè)務需求靈活調整區(qū)段劃分。但其依賴于及其時鐘,而且過長,且由于涉及到分布式環(huán)境,每臺及其上的時鐘不可能完全同步,可能會出現不是全局遞增的情況。
除此之外還有很多的id設計方案,可以參考附加的鏈接。在這里由于篇幅就不予詳細講解了。
參考:
《分布式ID方案有哪些以及各自的優(yōu)劣勢,我們當如何選擇》
《分布式系統(tǒng)唯一ID生成方案匯總》
24. 常見的數據庫優(yōu)化方案,在你的項目中數據庫如何進行優(yōu)化的
這個問題請甩給DBA,如果沒有DBA。。。
數據庫物理層:
- 數據庫系統(tǒng)軟件應該盡量跟數據文件分置不同存儲設備
- 如果可能,數據庫臨時空間,log盡量使用快速存儲設備。
- 數據文件應該根據具體應用需要分置于不同存儲設備來提高讀取效率
- 數據文件使用RAID。RAID5無敵!
數據庫邏輯層:
- 為數據庫的system表空間,user表空間,應用表弓箭分離。如果可能,三類表空間應該分在不同的物理存儲上。
- 應用表空間中表的表空間,索引的表空間也應該分離
- 創(chuàng)建表時應考慮表所存儲數據的業(yè)務特性在創(chuàng)建時定義不同的起始空間和空間增長方案,以盡量讓一條記錄處于一個連續(xù)的物理存儲空間來提高讀取效率。
- 制定不同的備份恢復和碎片整理機制
- 索引并不是越多越好,數據變化頻繁的表還應該建立索引定期重建機制,否則索引不但不會改善性能還會降低性能。
數據應用層:
- modeling必須要合理,數據庫建模是重中之重。一個良好設計的數據庫天生就具有優(yōu)勢,而一個設計不合理的數據庫再怎么優(yōu)化也是難以解決問題的。
- sql語句優(yōu)化。這點太大了,比如查詢盡量使用索引,盡量避免全表掃描,慎用子查詢和Union all,奪標join時盡量用小表去join大表。