一、MySQL存在的問題
-
優化器對復雜SQL支持不好
-
對SQL標准支持不好
-
大規模集群方案不成熟,主要指中間件
-
ID生成器,全局自增ID
-
異步邏輯復制,數據安全性問題
-
Online DDL
-
HA方案不完善
-
備份和恢復方案還是比較復雜,需要依賴外部組件
-
展現給用戶信息過少,排查問題困難
-
眾多分支,讓人難以選擇
二、數據庫環境介紹
通常來講,各個互聯網公司的數據庫分為5個數據庫環境:
-
dev : 開發環境, 開發可讀寫,可修改表結構; 常用的163的數據庫表; 開發人員可以修改表結構, 可以隨意修改其中的數據; 但是需要保證不影響其他開發同事
-
qa : 測試環境, 開發可讀寫, 開發人員可以通過工具修改表結構
-
sim: 模擬環境, 開發可讀寫, 通過web平台;發起上線請求時,會先在這個環境上進行預執行, 這個環境也可供部署上線演練或壓力測試使用 可以讀寫
-
real: 生產數據庫從庫(准實時同步),只讀環境,不允許修改數據,不允許修改表結構; 供線上問題查找,數據查詢等使用
-
online: 線上環境;開發人員不允許直接在線上環境進行數據庫操作,如果需要操作必須找DBA進行操作並進行相應記錄
這些環境的機器,一定要做到權限划分明確,讀寫帳號分離,並且有辨識度,能區分具體業務。例如用戶名w_wap, r_wap 能看出來,讀寫帳號是wap應用的
三、數據庫開發規范
開發規范本身也包含幾部分:基本命名和約束規范,字段設計規范,索引規范,使用規范等
規范存在意義
-
保證線上數據庫schema規范
-
減少出問題概率
-
方便自動化管理
-
規范需要長期堅持,對開發和DBA是一個雙贏的事情
約束規范
-
表字符集選擇UTF8 ,如果需要存儲emoj表情,需要使用UTF8mb4(MySQL 5.5.3以后支持)
-
存儲引擎使用InnoDB
-
變長字符串盡量使用VARCHAR VARBINARY
-
不在數據庫中存儲圖片、文件
- 設計表的時候需要添加注釋
-
單表數據量控制在1億以下,單表物理大小不超過10GB,行平均長度不超過8KB
-
禁止在線上做數據庫壓⼒測試
-
禁止從測試、開發環境直連數據庫
create database test_crm default character set=utf8;
基本命名規范
-
庫名、表名、字段名禁止使用保留字
-
庫名、表名、字段名、索引名使用小寫字母,以下划線分割 ,需要見名知意
-
庫名、表名、字段名、索引名不要設計過長,禁止超過32個字符,盡可能用最少的字符表達出表的用途
-
臨時庫、臨時表名必須以tmp為前綴,並以日期為后綴
- 備份庫、表必須以bak為前綴,並以日期為后綴
-
庫名、表名、字段名、索引名使用名詞作為數據庫名稱,並且只用英文,不用中文拼音
-
庫名使用英文字母,全部小寫,控制在3-7個字母以內
-
庫名如果有多個單詞,則使用下划線隔開,不建義駝峰命名
分表規范
-
禁止使用分區表
-
拆分大字段和訪問頻率低的字段,分離冷熱數據
-
使用HASH進行散表,表名后綴使用十進制數,下標從0開始
-
按⽇期時間分表需符合YYYY[MM][DD][HH]格式
-
采用合適的分庫分表策略
字段規范
-
所有字段均定義為NOT NULL ,除非你真的想存NULL,但是我想不到需要用Null的情況
-
字段類型在滿足需求條件下越小越好,使用UNSIGNED存儲非負整數 ,實際使用時候存儲負數場景不多
-
使用TIMESTAMP存儲時間,使用UNSIGNED INT存儲IPv4 地址而不是CHAR(15) ,這種方式只能存儲IPv4,存儲不了IPv6
-
使用VARCHAR存儲變長字符串 ,當然要注意varchar(M)里的M指的是字符數不是字節數;
-
使用DECIMAL代替FLOAT和DOUBLE存儲精確浮點數
-
盡可能不用BLOB TEXT
-
使用TINYINT來代替ENUM類型,將字符轉化為數字
-
禁止在數據庫中存儲明文密碼
-
使用VARBINARY存儲大小寫敏感的變⻓字符串
索引規范
-
單個索引字段數不超過5,單表索引數量不超過5,索引設計遵循B+ Tree索引最左前綴匹配原則
-
選擇區分度高的列作為索引,區分度高的放在前面
- 對字符串使用前綴索引,前綴索引長度不超過8個字符
-
建議優先考慮前綴索引,必要時可添加偽列並建立索引
-
建立的索引能覆蓋80%主要的查詢,不求全,解決問題的主要矛盾
-
DML和order by和group by字段要建立合適的索引
-
避免索引的隱式轉換
-
避免冗余索引
- 關於主鍵:表必須有主鍵 ;不使用更新頻繁的列 ;不選擇字符串列 ;不使用UUID MD5 HASH ;默認使用非空的唯一鍵 ,建議選擇自增或發號器
-
重要的SQL必須被索引:UPDATE、DELETE語句的WHERE條件列;ORDER BY、GROUP BY、DISTINCT的字段;多表JOIN的字段
-
核心SQL優先考慮覆蓋索引
-
不在低基數列上建立索引,例如“性別”
-
不在索引列進行數學運算和函數運算
-
盡量不使⽤外鍵 ,外鍵用來保護參照完整性,可在業務端實現;對父親和子表的操作會相互影響,降低可用性 ;INNODB本身對online DDL的限制
-
不使⽤%前導的查詢,如like “%ab”
-
不使用負向查詢,如not in/like "無法使用索引,導致全表掃描
隱式轉換例子,字段定義為varchar,但傳入的值是個int,就會導致全表掃描,要求程序端要做好類型檢查
字段:remark varchar(50) NOT Null
mysql>SELECT id, gift_code FROM gift WHERE deal_id = 640 AND remark=115127; 1 row in set (0.14 sec) mysql>SELECT id, gift_code FROM pool_gift WHEREdeal_id = 640 AND remark=‘115127’; 1 row in set (0.005 sec)
SQL類規范
-
使⽤預編譯語句,只傳參數,比傳遞SQL語句更高效,降低SQL注用概率
-
充分利用前綴索引
-
盡量不使用存儲過程、觸發器、函數等,讓數據庫做最擅長的事
-
避免使用大表的JOIN,MySQL優化器對join優化策略過於簡單
-
避免在數據庫中進行數學運算和其他大量計算任務
-
SQL合並,主要是指的DML時候多個value合並,減少和數據庫交互
-
合理的分頁,尤其大分頁
-
UPDATE、DELETE語句不使用LIMIT ,容易造成主從不一致
-
使用in代替or,in的值不超過1000個
-
禁止使用order by rand()
-
sql語句避免使用臨時表
-
使用union all而不是union
-
程序應有捕獲SQL異常的處理機制
-
禁止單條SQL語句同時更新多個表
- 讀取數據時,只選取所需要的列,不要每次都SELECT *,避免產生嚴重的隨機讀問題,尤其是讀到一些TEXT/BLOB列
-
通常情況下,子查詢的性能比較差,建議改造成JOIN寫法
-
多表聯接查詢時,關聯字段類型盡量一致,並且都要有索引
-
多表連接查詢時,把結果集小的表(注意,這里是指過濾后的結果集,不一定是全表數據量小的)作為驅動表
-
多表聯接並且有排序時,排序字段必須是驅動表里的,否則排序列無法用到索引
-
多用復合索引,少用多個獨立索引,尤其是一些基數(Cardinality)太小(比如說,該列的唯一值總數少於255)的列就不要創建獨立索引了
-
類似分頁功能的SQL,建議先用主鍵關聯,然后返回結果集,效率會高很多
四、DBA規范
版本選擇
-
MySQL社區版,用戶群體最大
-
MySQL企業版,收費
-
Percona Server版,新特性多
-
MariaDB版,國內用戶不多
建議選擇優先級為:MySQL社區版 > Percona Server > MariaDB > MySQL 企業版
主要內容
-
SQL審核,DDL審核和操作時間,尤其是OnlineDDL
-
高危操作檢查,Drop前做好數據備份
-
日志分析,主要是指的MySQL慢日志和錯誤日志
-
數據備份方案
Online DDL
原生MySQL執行DDL時需要鎖表,且鎖表期間業務是無法寫入數據的,對服務影響很大,MySQL對這方面的支持是比較差的
推薦使用pt-online-schema-change
使用pt-online-schema-change的優點有:
-
無阻塞寫入
-
完善的條件檢測和延時負載策略控制
使用pt-online-schema-change的限制有:
-
改表時間會比較長(相比直接alter table改表)
-
修改的表需要有唯一鍵或主鍵
-
在同一端口上的並發修改不能太多
MySQL集群方案
-
基於主從復制;
-
基於中間件/proxy
-
基於NDB引擎
-
基於Galera協議
優先推薦MHA:可以采用一主多從,或者雙主多從的模式,這種模式下,可以采用MHA或MMM來管理整個集群,最新的MHA也已支持MySQL 5.6的GTID模式了
MHA的優勢很明顯:
-
開源,用Perl開發,代碼結構清晰,二次開發容易;
-
方案成熟,故障切換時,MHA會做到較嚴格的判斷,盡量減少數據丟失,保證數據一致性;
-
提供一個通用框架,可根據自己的情況做自定義開發,尤其是判斷和切換操作步驟;
-
支持binlog server,可提高binlog傳送效率,進一步減少數據丟失風險。
不過MHA也有些限制:
-
需要在各個節點間打通ssh信任,這對某些公司安全制度來說是個挑戰,因為如果某個節點被黑客攻破的話,其他節點也會跟着遭殃;
-
自帶提供的腳本還需要進一步補充完善,當然了,一般的使用還是夠用的。
拆分問題
-
解決單機寫入壓力過大和容量問題
-
有垂直拆分和水平拆分兩種方式
-
拆分要適度,切勿過度拆分
-
有中間層控制拆分邏輯最好,否則拆分過細管理成本會很高
數據備份
-
全量備份 VS 增量備份
-
熱備 VS 冷備
-
物理備份 VS 邏輯備份
-
延時備份
-
全量binlog備份
建議方式:
-
熱備+物理備份
-
核心業務:延時備份+邏輯備份
-
全量binlog備份
主要做的幾點:
-
備份策略集中式調度管理
-
xtrabackup熱備
-
備份結果統計分析
-
備份數據一致性校驗
-
采用分布式文件系統存儲備份
備份系統采用分布式文件系統原因:
-
解決存儲分配的問題
-
解決存儲NFS備份效率低下問題
-
存儲集中式管理
-
數據可靠性更好
