從上圖可見,自頂向下的一共有四層,分別是硬件、存儲系統(tǒng)、存儲結(jié)構(gòu)、具體實現(xiàn)。層與層之間是緊密聯(lián)系的,每一層的上層是該層的載體;因此越往頂層越能決定性能的上限,同時優(yōu)化的成本也相對會比較高,性價比也隨之越低。以最底層的具體實現(xiàn)為例,那么索引的優(yōu)化的成本應該是最小的,可以說加了索引后無論是 CPU 消耗還是響應時間都是立竿見影降低。然而一個簡單的語句,無論如何優(yōu)化加索引也是有局限的,當在具體實現(xiàn)這層沒有任何優(yōu)化空間的時候就得往上一層【存儲結(jié)構(gòu)】思考,思考是否從物理表設計的層面出發(fā)優(yōu)化(如分庫分表、壓縮數(shù)據(jù)量等),如果是文檔型數(shù)據(jù)庫得思考下文檔聚合的結(jié)果。如果在存儲結(jié)構(gòu)這層優(yōu)化得沒效果,得繼續(xù)往再上一次進行考慮,是否關(guān)系型數(shù)據(jù)庫應該不適合用在現(xiàn)在得業(yè)務場景?如果要換存儲,那么得換怎樣得 NoSQL?所以咱們優(yōu)化的思路,出于性價比的優(yōu)先考慮具體實現(xiàn),實在沒有優(yōu)化空間了再往上一層考慮。當然如果公司有錢,直接使用鈔能力,繞過了前面三層,這也是一種便捷的應急處理方式。該篇文章不討論頂與底的兩個層面的優(yōu)化,主要從存儲結(jié)構(gòu)、存儲系統(tǒng)中間兩層的角度出發(fā)進行探討。
注意點:別一次性遷移數(shù)量過多,建議低頻率多次限量遷移。像 MySQL 由于刪除數(shù)據(jù)后是不會釋放空間的,可以執(zhí)行命令 OPTIMIZE TABLE 釋放存儲空間,但是會鎖表,如果存儲空間還滿足,可以不執(zhí)行。建議優(yōu)先考慮該方案,主要通過數(shù)據(jù)庫作業(yè)把非熱點數(shù)據(jù)遷移到歷史表,如果需要查歷史數(shù)據(jù),可新增業(yè)務入口路由到對應的歷史表(庫)。
在數(shù)據(jù)庫以序列化存儲的方式,對于一些不需要結(jié)構(gòu)化存儲的業(yè)務來說是一種很好減少數(shù)據(jù)量的方式,特別是對于一些 M*N 的數(shù)據(jù)量的業(yè)務場景,如果以 M 作為主表優(yōu)化,那么就可以把數(shù)據(jù)量維持最多是 M 的量級。另外像訂單的地址信息,這種業(yè)務一般是不需要根據(jù)里面的字段檢索出來,也比較適合。這種方案我認為屬于一種臨時性的優(yōu)化方案,無論是從序列化后丟失了部份字段的查詢能力,還是這方案的可優(yōu)化性都是有限的。
當緩存沒有數(shù)據(jù),就得跑去數(shù)據(jù)庫查詢出來,這就是緩存穿透。假如某個時間臨界點數(shù)據(jù)是空的例如周排行榜,穿透過去的無論查找多少次數(shù)據(jù)庫仍然是空,而且該查詢消耗 CPU 相對比較高,并發(fā)一進來因為缺少了緩存層的對高并發(fā)的應對,這個時候就會因為并發(fā)導致數(shù)據(jù)庫資源消耗過高,這就是緩存擊穿。數(shù)據(jù)庫資源消耗過高就會導致其他查詢超時等問題。該問題的解決方案也簡單,對于查詢到數(shù)據(jù)庫的空結(jié)果也緩存起來,但是給一個相對快過期的時間。有些同行可能又會問,這樣不就會造成了數(shù)據(jù)不一致了么?一般有數(shù)據(jù)同步的方案像分布式緩存、后續(xù)會說的一主多從、CQRS,只要存在數(shù)據(jù)同步這幾個字,那就意味著會存在數(shù)據(jù)一致性的問題,因此如果使用上述方案,對應的業(yè)務場景應允許容忍一定的數(shù)據(jù)不一致。