一、涉及業務上的修改/刪除數據,在獲得業務方、CTO的郵件批准後方可執行,執行前提早作好備份,必要時可逆。css
二、全部上線需求必須走工單系統,口頭通知視爲無效。java
三、在對大表作表結構變動時,如修改字段屬性會形成鎖表,並會形成從庫延遲,從而影響線上業務,必須在凌晨0:00 後業務低峯期執行,另統一用工具 pt-online-schema-change 避免鎖表且下降延遲執行時間。mysql
使用範例:sql
#pt-online-schema-change --alter="add index IX_id_no(id_no)" \ --no-check-replication-filters --recursion-method=none --user=dba \ --password=123456 D=test,t=t1 --execute
對於MongoDB建立索引要在後臺建立,避免鎖表。shell
使用範例:數據庫
db.t1.createIndex({idCardNum:1},{background:1})
四、全部線上業務庫均必須搭建MHA高可用架構,避免單點問題。後端
五、給業務方開權限時,密碼要用MD5加密,至少16位。權限如沒有特殊要求,均爲select查詢權限,並作庫表級限制。bash
六、刪除默認空密碼帳號。網絡
delete from mysql.user where user='' and password=''; flush privileges;
七、彙總庫開啓Audit審計日誌功能,出現問題時方可追溯。架構
八、禁止一個MySQL實例存放多個業務數據庫,會形成業務耦合性太高,一旦出現問題會殃及池魚,增長了定位故障問題的難度。一般採用多實例解決,一個實例一個業務庫,互不干擾。
九、禁止在主庫上執行後臺管理和統計類的功能查詢,這種複雜類的SQL會形成CPU的升高,進而會影響業務。
十、批量清洗數據,須要開發和DBA共同進行審查,應避開業務高峯期時段執行,並在執行過程當中觀察服務狀態。
十一、促銷活動等應提早與DBA當面溝通,進行流量評估,好比提早一週增長機器內存或擴展架構,防止DB出現性能瓶頸。
十二、禁止在線上作數據庫壓力測試。
1三、禁止在數據庫中存儲明文密碼。
1四、使用InnoDB存儲引擎。
1五、表字符集統一使用UTF8。
1六、全部表和字段都須要添加中文註釋。
1七、不在數據庫中存儲圖片、文件等大數據。
1八、避免使用存儲過程、視圖、觸發器、事件。
MySQL是OLTP應用,最擅長簡單的增、刪、改、查操做,但對邏輯計算分析類的應用,並不適合,因此這部分的需求最好經過程序上實現。
1九、避免使用外鍵,外鍵用來保護參照完整性,可在業務端實現。
20、對事務一致性要求不高的業務,如日誌表等,優先選擇存入MongoDB。
2一、表必須有主鍵,例如自增主鍵。
2二、禁止使用分區表。
2三、用DECIMAL代替FLOAT和DOUBLE存儲精確浮點數。
浮點數的缺點是會引發精度問題,請看下面一個例子:
mysql> CREATE TABLE t3 (c1 float(10,2),c2 decimal(10,2)); Query OK, 0 rows affected (0.05 sec) >mysql> insert into t3 values (999998.02, 999998.02); Query OK, 1 row affected (0.01 sec) >mysql> select * from t3; +-----------+-----------+ | c1 | c2 | +-----------+-----------+ | 999998.00 | 999998.02 | +-----------+-----------+ 1 row in set (0.00 sec)
能夠看到c1列的值由999998.02變成了999998.00,這就是float浮點數類型的不精確性形成的。所以對貨幣等對精度敏感的數據,應該用定點數表示或存儲。
2四、使用TINYINT來代替ENUM類型。
2五、字段長度儘可能按實際須要進行分配,不要隨意分配一個很大的容量。
選擇字段的通常原則是保小不保大,能用佔用字節少的字段就不用大字段。好比主鍵,強烈建議用int整型,不用uuid,爲何?省空間啊。空間是什麼?空間就是效率!按4個字節和按32個字節定位一條記錄,誰快誰慢太明顯了。涉及幾個表作join時,效果就更明顯了。更小的字段類型佔用的內存就更少,佔用的磁盤空間和磁盤I/O也會更少,並且還會佔用更少的帶寬。
有很多開發人員在設計表字段時,只要是針對數值類型的所有用int,但這不必定合適,就好比用戶的年齡,通常來講,年齡大都在1~100歲之間,長度只有3,那麼用int就不適合了,能夠用tinyint代替。又好比用戶在線狀態,0表示離線、1表示在線、2表示離開、3表示忙碌、4表示隱身等,其實相似這樣的狀況,用int都是沒有必要的,浪費空間,採用tinyint徹底能夠知足須要,int佔用的是4字節,而tinyint才佔用1個字節。
int整型有符號(signed)最大值是2147483647,而無符號(unsigned)最大值是4294967295,若是你的需求沒有存儲負數,那麼建議改爲有符號(unsigned),能夠增長int存儲範圍。
int(10)和int(1)沒有什麼區別,10和1僅是寬度而已,在設置了zerofill擴展屬性的時候有用,例:
root@localhost(test)10:39>create table test(id int(10) zerofill,id2 int(1)); Query OK, 0 rows affected (0.13 sec) root@localhost(test)10:39>insert into test values(1,1); Query OK, 1 row affected (0.04 sec) root@localhost(test)10:56>insert into test values(1000000000,1000000000); Query OK, 1 row affected (0.05 sec) root@localhost(test)10:56>select * from test; +------------+------------+ | id | id2 | +------------+------------+ | 0000000001 | 1 | | 1000000000 | 1000000000 | +------------+------------+ 2 rows in set (0.01 sec)
2六、字段定義爲NOT NULL要提供默認值。
從應用層角度來看,能夠減小程序判斷代碼,好比你要查詢一條記錄,若是沒默認值,你是否是得先判斷該字段對應變量是否被設置,若是沒有,你得經過java把該變量置爲''或者0,若是設了默認值,判斷條件可直接略過。
NULL值很難進行查詢優化,它會使索引統計更加複雜,還須要MySQL內部進行特殊處理。
2七、儘量不使用TEXT、BLOB類型。
2八、索引不是越多越好,按實際須要進行建立。
2九、查詢的字段必須建立索引。
30、不在索引列進行數學運算和函數運算。
沒法使用索引,致使全表掃描。
例:SELECT * FROM t WHERE YEAR(d) >= 2016;
因爲MySQL不像Oracle那樣支持函數索引,即便d字段有索引,也會直接全表掃描。
應改成----->SELECT * FROM t WHERE d >= '2016-01-01';
3一、不在低基數列上創建索引,例如‘性別’。
有時候,進行全表瀏覽要比必須讀取索引和數據表更快,尤爲是當索引包含的是平均分佈的數據集是更是如此。對此典型的例子是性別,它有兩個均勻分佈的值(男和女)。經過性別須要讀取大概一半的行。在種狀況下進行全表掃描瀏覽要更快。
3二、不使用%前導的查詢,如like ‘%xxx’。
沒法使用索引,致使全表掃描。
低效查詢
SELECT * FROM t WHERE name LIKE '%de%'; -----> 高效查詢 SELECT * FROM t WHERE name LIKE 'de%';
3三、不使用反向查詢,如 not in / not like。
沒法使用索引,致使全表掃描。
3四、避免冗餘或重複索引。
聯合索引IX_a_b_c(a,b,c) 至關於 (a) 、(a,b) 、(a,b,c),那麼索引 (a) 、(a,b) 就是多餘的。
*3五、不使用SELECT ,只獲取必要的字段。**
消耗CPU和IO、消耗網絡帶寬;
沒法使用覆蓋索引。
3六、用IN來替換OR。
低效查詢
SELECT * FROM t WHERE LOC_ID = 10 OR LOC_ID = 20 OR LOC_ID = 30; -----> 高效查詢 SELECT * FROM t WHERE LOC_IN IN (10,20,30);
3七、避免數據類型不一致。
SELECT * FROM t WHERE id = '19'; -----> SELECT * FROM t WHERE id = 19;
3八、減小與數據庫的交互次數。
INSERT INTO t (id, name) VALUES(1,'Bea'); INSERT INTO t (id, name) VALUES(2,'Belle'); INSERT INTO t (id, name) VALUES(3,'Bernice'); -----> INSERT INTO t (id, name) VALUES(1,'Bea'), (2,'Belle'),(3,'Bernice'); Update … where id in (1,2,3,4); Alter table tbl_name add column col1, add column col2;
3九、拒絕大SQL,拆分紅小SQL。
低效查詢
SELECT * FROM tag JOIN tag_post ON tag_post.tag_id = tag.id JOIN post ON tag_post.post_id = post.id WHERE tag.tag = 'mysql'; 能夠分解成下面這些查詢來代替 -----> 高效查詢 SELECT * FROM tag WHERE tag = 'mysql' SELECT * FROM tag_post WHERE tag_id = 1234 SELECT * FROM post WHERE post_id in (123, 456, 567, 9098, 8904);
40、禁止使用order by rand()
SELECT * FROM t1 WHERE 1=1 ORDER BY RAND() LIMIT 4; ----> SELECT * FROM t1 WHERE id >= CEIL(RAND()*1000) LIMIT 4;