[別被脫褲系列]2 還沒深入數據庫就淺出了

上一部分一起學習了數據庫中的ACID等特性。數據庫面試系列第二部分分享數據庫的調優常用步驟,索引底層原理,頁機制等。總體思維導圖如下所示。

1 定位

主要從三個方面進行定位,用戶的反饋,日誌記錄以及服務器內網監控。

  • 用戶反饋

用戶是最直接的反饋者,用戶的反饋是推向系統進一步優化的重要一步。

  • 服務器資源監控

儘量不要等着用戶反饋的時候手忙腳亂。通常項目中都會有一套比較完整的服務端監控體系,所謂"監控不到位,領導兩行淚"。那監控一般都是哪些內容呢?服務器本身CPU,IO等基礎指標以外,通常會通過訪問趨勢表展示服務整體的訪問量、響應供應時間情況,錯誤數量等。通過性能報表展示哪個資源或者服務出現問題。

監控指標
監控指標
  • 日誌分析

除了Linux系統日誌,還有數據庫日誌,根據他們定位問題所在。

Linux日誌
Linux日誌

數據調優的幾個方向

  • 數據庫的選擇

根據應用,業務的需要選擇不同的數據庫。是否考慮事務,行存儲還是列存儲等。

  • 優化表

(1) 如果查詢分析較多,可採用空間換時間的方式增加冗餘字段提高查詢效率。

(2) 不同字段的數據類型直接關係到查詢效率的高低和存儲的大小。

(3) 採用第三範式讓結構更加清晰,減少冗餘字段。

  • 合理使用索引

(1) 不是索引越多越好,索引也需佔用存儲空間,同時也會增加篩選索引的計算時間。

(2) 數據的重複度過高不宜使用索引。

(3) 索引列處於不同的位置對索引影響比較大。比如在WHERE子句中,對索引字段進行計算會造成索引失效。

  • 使用redis等作爲緩存

緩存分爲靜態緩存,分佈式緩存,熱點緩存。"緩存"我的理解是解決不同硬件速度的差異性,協調且充分利用硬件的資源。使用緩存的案例無處不在,不管是Linux內核管理TLB,還是HTTP的緩存機制。總之很多地方都會通過使用緩存來提高訪問速度,儘量減少和數據庫的直接交互。

  • 庫級優化

(1) 在讀寫都比較多情況下,通過採用讀寫分離的方式降低數據庫的負載。

(2) 數據庫的分庫分表。切分數據庫到多臺服務器。

2 索引的原理

索引看做字典的目錄,根據目錄能快速定位內容,不用從頭到尾花費時間找。是不是加了索引就是起飛了?那是不一定的。

(1) 數據量小的情況,不加索引

(2) 數據流大的情況,考慮加索引

索引的種類

(1)普通索引

沒有約束

(2)唯一性索引

增加唯一性約束,一張數據表可以多個唯一索引

(3)主鍵索引

在唯一性索引基礎上,增加不爲空的約束。

(4)全文索引

Mysql自帶全文索引支持英文,通常使用ES等代替

聚集索引與非聚集

(1) 聚集索引

通過索引位置直接找到需要的值。如下圖

(2) 非聚集索引

索引項順序存儲,但是指向內容爲隨機。所以第一次找到索引,還需要第二次去找到索引對應的位置從而取出數據行。如下圖所示。

(3) 兩者不同點

  • 聚集索引葉子節點存放數據值。非聚集索引葉子節點存放數據行的位置
  • 一個表只能一個聚集索引但是可以有多個非聚集索引
  • 聚集索引查詢效率高,非聚集索引查詢效率低

適合加索引

  • 字段唯一性性質

我們知道唯一性索引和主鍵索引都具有唯一性的約束,如果某字段唯一則可以考慮

  • 需要經常Group by和ORDER by的情況
  • 索引是讓數據按照某種順序進行存儲和檢索。
  • distinct字段需要創建索引

什麼時候不需要創建索引

  • WHERE條件中用不到的字段不需要創建索引
  • 表記錄太少
  • 字段中大量重複
  • 頻繁更新的字段。更新字段也更新索引,索引多,更新索引的時候會成爲負擔。

失效的索引

  • 使用表達式比如EXPLAIN查看錶執行計劃時索引會失效

EXPLAIN SELECT name from..

  • 對索引使用函數也會失效
  • 使用"like"進行模糊查詢的時候不要使用"%",不然也會失效

二叉樹

二分查找是一種高效的檢索方式,時間複雜度爲O(log2n),但是在特殊的情況退化爲鏈表從而導致時間複雜度爲o(n)。隨後提出平衡二叉樹的概念,但是二叉樹中樹的深度還是O(log2n),數據查詢依賴於磁盤IO,從而改造了M叉樹。比如B樹,對於一個1000階的B樹,只需要三層就可以存儲1000W的索引數據,因爲高度比二叉樹低很多。爲了提高查詢的穩定性,出現B+樹。

這裏也就出現一個面試題

B樹和B+樹

  • B+樹查詢更穩定,因爲在查詢過程中都是在葉子節點才能找到數據。B樹中非葉子節點也會存儲數據
  • B+樹更矮胖,查詢時所需磁盤IO更少。相同的磁盤頁,B+樹能存放更多節點關鍵字。

3 頁結構

在數據庫中,不管是讀取一行還是多行都是將所在的頁進行加載。頁是數據庫管理存儲的空間的基本單位。

在數據庫中存在頁,區,段等概念,他們之間的關係如下圖所示。

數據庫頁區段
數據庫頁區段

從上圖我們知道一個表空間存在多個段,其中一個段包含多個區,一個區存在多個頁,每個頁多行記錄。那具體都是幹啥的呢?

在Innodb中,一個區分配64連續的頁,頁大小默認爲16KB,所以一個區大小爲64*16KB=1MB

段是由多個區組成,不同數據庫對象不同段。創建一張表的時候創建一個表段。創建索引則爲索引段。

表空間

邏輯容器。其中包含很多段,但是一個段只能屬於一個表空間。一個數據庫由多個表空間組成,其中包含系統表空間,用戶表空間等。

數據庫IO操作最小單位爲頁。頁的具體結構如下圖所示。

爲了知道頁中各個字段是什麼意思,總結了一個圖表如下

上面的文件頭和文件尾對頁內容進行封裝,通過校驗的方式保證頁的完整性。同時通過鏈表的方式將各個頁連接在一起。如下圖所示。

再看記錄部分。其中記錄部分包含了最大,最小記錄和用戶記錄,另外還有可變的空閒空間方便靈活的分配新的記錄。

索引部分

在頁中記錄按照單鏈表的方式存儲。我們知道單鏈表的插入和刪除方便,但是查找就不是很有好了。所以在此引入頁目錄,頁目錄提供二分查找的方式提高記錄的檢索效率。那具體是怎麼樣的呢?

  • 先對記錄分組,第一組只有一個記錄,最後一組爲最大記錄
  • 每一組最後一條記錄存儲一共多少條記錄。
  • 頁目錄存儲最後一條記錄的地址偏移量,也叫做槽,其指針指向組的最後一個記錄。

假設查找鍵爲6的用戶,頁目錄下標從0開始,採用二分查找進行。 (1) mid=(low+high)/2=1,此時取出槽1最大記錄爲4,4<6則在[mid,high]中尋找 (2) mid=(mid+high)/2=2,此時取出槽2最大記錄爲8,8>6,直接在槽2查找,遍歷取出即可。

3 悲觀鎖與樂觀鎖

鎖運用到很多地方,我們熟知的多線程,線程同步等都可能用到鎖,通過鎖來調整運行順序和保持一致性。在數據庫中,按照粒度劃分爲行鎖,表鎖和頁鎖。

(1) 行鎖

優點:鎖粒度較小,鎖衝突概率小,併發度較高。缺點:鎖開銷大,容易出現死鎖

(2) 頁鎖

從前面總結我們知道頁中包含行,那麼頁鎖數據資源比行鎖多。開銷在行和表鎖之間,會出現死鎖。

(3) 表鎖

優點:鎖使用開銷小,加鎖快。缺點:鎖定力度大,發生鎖衝突概率大。

從數據庫的管理角度來區分,分爲共享鎖和排它鎖

(1) 共享鎖

可以被用戶讀取,但是不能修改。

(2)排它鎖

也叫做獨佔鎖,寫鎖或者X 鎖。只允許進行鎖定的事務使用,其他事務無法對其修改或者查詢。所以我們在使用更新操作的時候,爲了防止其他事物的更改,就會使用排它鎖。

從開發者角度分爲樂觀鎖與悲觀鎖

樂觀鎖:通過自身採用時間戳或者版本機制進行控制。悲觀鎖:通過數據庫自身機制保證數據操作的排他性

4 SQL分析常用步驟

(1) 檢查有沒有出現有沒有週期性的規律,如果有可以考慮更新緩存的策略或者加緩存

(2) 如果不是,考慮是不是查詢語句本身問題,從而分析查詢語句。之前介紹的幾種查詢優化的方法都可以嘗試。同時引入慢查詢可以知道執行慢的語句有哪些

(3) 找到了執行慢的語句就可以引入explain查看SQL執行計劃,通過expalin可以知道數據表讀取順序,實際使用的索引,被優化行的數量等。

(4) 最後使用show profile瞭解執行成本。默認是關着的,使用set 'profiling'="on"打開。

這一篇就到尾聲了,謝謝大家的查看,也麻煩大家文末點個在看。再見,下一期常見面試題彙總見。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章