前言
目前大部分公司的數據庫都是MySQL,雖然如今NoSQL數據庫好比mongo, hbase愈來愈流行了,但傳統的MySQL依然是業界用得最多。本文是以MySQL爲例。javascript
數據庫
數據庫是惟一在應用系統中的單點資源,對於數據庫的資源的使用要特別當心。有以下幾點注意點java
- 數據庫做爲數據存儲的地方,不該該把寶貴的資源用於數據的轉換或統計操做,SQL中不使用一些字符轉換等操做。
- 數據庫鏈接資源寶貴,外圍系統按需分配使用
- 數據庫不怕高qps的小查詢,但懼怕慢查詢,所以請消滅慢查詢。
- 索引不是越多越好,維護索引資源也耗費數據庫運算資源,數據庫運算能力寶貴程度大於存儲
- 若是是主從架構,主機器與從機器的網絡帶寬及穩定性要保證 不在數據庫中存儲圖片、文件等大數據
- 禁止在線上作數據庫壓力測試
- 禁止從測試、開發環境直連線上數據庫
- 不在業務高峯期批量更新、查詢數據庫
- 不在MySQL數據庫中存放業務邏輯,寫儲存過程及觸發器等
- 禁止在主庫上執行後臺管理和統計報表類的功能查詢,都放到從庫
硬件
MySQL每秒鐘都在進行大量、複雜的查詢操做,對磁盤的讀寫量可想而知。因此,一般認爲磁盤I/O是制約MySQL性能的最大因素之一,推薦使用RAID-0+1磁盤陣列。數據庫
推薦使用至少4U以上的服務器來專門作數據庫服務器,基本上是越多越好服務器
服務器內存建議不要小於4GB。基本上是越大越好網絡
系統配置
MySQL配置在my.conf,影響新能的幾個關鍵配置屬性架構
- 使用INNODB存儲引擎 5.5之後的默認引擘,支持事務,行級鎖,更好的恢復性,高併發下性能更好,對多核,大內存,ssd等硬件支持更好。
- 表字符集使用utf8mb4
使用utf8mb4字符集,若是是漢字,佔3個字節,但ASCII碼字符仍是1個字節;統一,不會有轉換產生亂碼風險,並能解決符號表情亂碼問題;
- max_connections 最大鏈接(用戶)數
- innodb_log_file_size
在高寫入負載尤爲是大數據集的狀況下很重要。這個值越大則性能相對越高,可是要注意到可能會增長恢復時間。設置爲64-512MB,根據服務器大小而異
- Innodb_buffer_pool_pages_data 分配出去, 正在被使用頁的數量
- Innodb_buffer_pool_pages_total 緩衝區總共的頁面數 Innodb_page_size
編譯的InnoDB頁大小(默認16KB)
調優參考計算方法:併發
val = Innodb_buffer_pool_pages_data / Innodb_buffer_pool_pages_total * 100%
- val > 95% 則考慮增大 innodb_buffer_pool_size, 建議使用物理內存的75%
- val < 95% 則考慮減少 innodb_buffer_pool_size,
- 建議設置爲:
Innodb_buffer_pool_pages_data * Innodb_page_size * 1.05 / (1024*1024*1024)
數據庫表結構
表結構的設計目標除了知足業務之外,儘可能減小代碼實現上的聯表查詢操做,所以在設計上能夠適當有一些冗餘字段的設計,減小數據庫IO次數。函數
如今很流行的ElasticSearch等大數據存儲寬表的概念也是這種思想的體現
- 儘可能避免使用分區表 MySQL的分區表實際性能不是很好。 拆分大字段和訪問頻率低的字段,分離冷熱數據
- 採用合理的分庫分表策略,推薦使用HASH進行分表,表名後綴使用十進制數,下標從0開始首次分表儘可能多的分,避免二次分表,二次分表的難度和成本較高
- 單表字段數控制在20個之內
- 一條完整的建表語句中應包含必要的字段、主鍵、合理的索引(綜合代碼中全部的條件語句建立合理的索引,主鍵必需要有
索引設計
索引是一把雙刃劍,它能夠提升查詢效率但也會下降插入和更新的速度並佔用磁盤空間。高併發
- 單張表中索引數量不超過5個
- 單個索引中的字段數不超過5個
- 對字符串使用前綴索引,前綴索引長度不超過10個字符;若是有一個CHAR(200)列,若是在前10個字符內,多數值是唯一的,那麼就不要對整個列進行索引。對前10個字符進行索引可以節省大量索引空間,也可能會使查詢更快
- 表必須有主鍵,不使用UUID、MD五、HASH做爲主鍵,儘可能不選擇字符串列做爲主鍵;主鍵建議選擇自增id
- 建立複合索引時區分度較大的字段放在最前面
- 不在低區分度的字段上建立索引,如「性別」
- 避免冗餘或重複索引
- 合理建立聯合索引(避免冗餘),index(a、b、c) 至關於index(a)、index(a、b)、index(a、、b、c)
- 索引不是越多越好,按實際須要進行建立
- 每一個額外的索引都要佔用額外的磁盤空間,並下降寫操做的性能
- 不在索引列進行數學運算和函數運算;
- 儘可能不要使用外鍵 外鍵用來保護參照完整性,可在業務端實現,對父表和子表的操做會相互影響,下降可用性
- 不使用%前導的查詢,如like「%xxx」,不使用反向查詢,如not in / not like 沒法使用索引,致使全表掃描 1. 全表掃描致使buffer pool利用下降
字段設計
- 儘量不要使用TEXT、BLOB類型。刪除這種值會在數據表中留下很大的"空洞",能夠考慮把BLOB或TEXT列分離到單獨的表中
- 用DECIMAL代替FLOAT和DOUBLE存儲精確浮點數。浮點數相對於定點數的優勢是在長度必定的狀況下,浮點數可以表示更大的數據範圍;浮點數的缺點是會引發精度問題
- 將字符轉化爲數字
- 使用TINYINT來代替ENUM類型
- 字段長度儘可能按實際須要進行分配,不要隨意分配一個很大的容量 VARCHAR(N),N表示的是字符數不是字節數,好比VARCHAR(255),能夠最大可存儲255個漢字,須要根據實際的寬度來選擇N。VARCHAR(N),N儘量小,由於6. 6.MySQL一個表中全部的VARCHAR字段最大長度是65535個字節,進行排序和建立臨時表一類的內存操做時,會使用N的長度申請內存;
- 若是可能, 全部字段均定義爲not null
- 使用UNSIGNED存儲非負整數 一樣的字節數,存儲的數值範圍更大。如tinyint有符號爲-128-127,無符號爲0-255
- 使用TIMESTAMP存儲時間. 由於TIMESTAMP使用4字節,DATETIME使用8個字節,同時TIMESTAMP具備自動賦值以及自動更新的特性.
- 使用INT UNSIGNED存儲IPV4
- 使用VARBINARY存儲大小寫敏感的變長字符串
- 禁止在數據庫中存儲明文密碼
思考題
- 數據庫有哪些高可用措施?
- 若是數據庫掛了,怎麼保證核心業務是可用的?