上一部分一起學習了數據庫中的ACID等特性。數據庫面試系列第二部分分享數據庫的調優常用步驟,索引底層原理,頁機制等。總體思維導圖如下所示。
1 定位
主要從三個方面進行定位,用戶的反饋,日誌記錄以及服務器內網監控。
用戶反饋
用戶是最直接的反饋者,用戶的反饋是推向系統進一步優化的重要一步。
服務器資源監控
儘量不要等着用戶反饋的時候手忙腳亂。通常項目中都會有一套比較完整的服務端監控體系,所謂"監控不到位,領導兩行淚"。那監控一般都是哪些內容呢?服務器本身CPU,IO等基礎指標以外,通常會通過訪問趨勢表展示服務整體的訪問量、響應供應時間情況,錯誤數量等。通過性能報表展示哪個資源或者服務出現問題。
日誌分析
除了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"打開。
這一篇就到尾聲了,謝謝大家的查看,也麻煩大家文末點個在看。再見,下一期常見面試題彙總見。