MySQL 社區規范 | 數據庫篇

前言 | 筆記歸檔

這周公司開發工作比較悠閑,工作幾乎壓在設計上游,于是整理了下公司開發的文檔,包括項目架構、服務器運維、規范、api對接、基本依賴信息等。如下是包含其中的MySQL開發規范,根據社區很多的博文參考以及結合自身小團隊開發情況總結。


命名規范

  • 對象名稱必須使用小寫,多單詞統一使用下劃線分割

  • 命名的單詞必須做到顧名思義、簡潔,表名長度不要超過16個字符,字段名稱長度不要超過32個字符

  • 禁止使用保留字并且盡量少用含有關鍵詞來命名

  • 臨時表必須以tmp_開頭、以日期結尾,備份表必須以bak_開頭、以日期結尾

基礎規范

  • 盡可能地使用InnoDB作為表的存儲引擎

    MySQL 5.6以后,InnoDB被設置成默認的存儲引擎,支持事務和行級鎖。

  • 數據庫和數據表統一使用UTF8MB4字符編碼

    UTF8MB4字符編碼支持中文儲存以及表情存儲,兼容性杠杠的。

  • 所有的表和字段必須添加注釋

    這個是好習慣的問題,即使做到了顧名思義,以防萬一哪天健忘或理解錯誤,同時給后人留下后路,提高維護性。使用comment設定注釋。

  • 盡量控制表行數在500萬以內

    數據量越多,則查詢的效率越低,同時會導致長時間占用高內存以及磁盤IO過高。數據量膨大建議采用分表、合理分區等方案。

  • 盡可能采用冷熱數據分離策略

    MySQL中,數據表列數最大限制為4096列 ,每條元祖數據總和大小不能超過65535字節,常用的字段與基本不常用的字段、細分不同業務的數據分開表設計存儲,減小表寬度,保證熱數據的內存緩存命中率,降低CPU使用率以及降低IO流。

  • 禁止以圖片、文件等二進制數據

    MySQL雖然支持對文件對象的存儲,但是開發人員是不允許、不推薦這樣做的。文件通常是很大的,轉成二進制數據將是一串很長的字符串,無疑占用數據庫很大的存儲空間,在數據庫讀寫更是消耗內存和占用大量的IO流,最終導致查詢的效率低下。一般文件是存放于文件服務器,將文件服務器的路徑存儲于數據庫中。

行為與流程規范

  • 禁止在線上做數據庫的壓力測試

  • 對應的環境使用對應的數據庫比如測試環境一定要使用測試環境的數據庫

  • super權限只能屬于DBA,不能賦予項目程序

  • 養成查看SQL運行性能的習慣,可以借用性能分析工具

    譬如:EXPLAIN語句 | showprofile | mySQLsla等。

  • 禁止在業務高峰期批量更新、查詢數據

    可以在流量比較低的凌晨跑批操作。

  • 活動推廣、系統上線以及平臺上新務必對流量進行評估

    防患于未然、否則可能造成數據庫服務器流量瓶頸進而導致影響業務。

  • 所有建表前都要確定字段的類型、長度以及索引方可建表

    確保表結構設計為最優是前期數據庫最大的優化

  • 所有對表的結構、數據的修改務必經過DBA的審閱和同意

表設計規范

  • 盡可能每張表的索引數量控制在5個以內

    索引具有提高查詢的效率的好處也有降低寫操作效率的壞處,甚至會降低查詢到的效率。同時索引也是占用內存空間的,因而應該合理控制索引的數量。

  • 每一張InnoDB表都必須含有一個主鍵

    InnoDB 是一種索引組織表:數據的存儲的邏輯順序和索引的順序是相同的。每個表都可以有多個索引,但是表的存儲順序只能有一種 InnoDB是按照主鍵索引的順序來組織表的。不要使用可能會更新的列作為主鍵,同時盡量不要使用UUID、MD5、HASH等無序的字符串作為主鍵。在沒有特別的情況下,要使用自增的整型或發號器作為主鍵。

  • 盡可能避免使用外鍵約束

    外鍵可以保證數據的準確性、參照完整性,每次進行寫操作時都會走校驗數據知否正確的流程,將會有損寫操作的性能,數據的參照完整性建議在業務層實現。倘若字表的寫操作很少的情況下務必使用外鍵約束。

  • 設置數據表架構應考慮后期擴展型

    體驗產品和架構師的交流和能力、對業務的熟悉度。

  • 遵循范式與冗余平衡原則

    第一范式:具有原子性

    第二范式:主鍵列與非主鍵列遵循完全函數依賴關系

    第三范式:非主鍵列之間沒有傳遞函數依賴關系

    合理的原則能夠體驗出數據庫的可操作性、穩定性以及性能nice。范式設計是數據結構的一種思想,但是我們應當靈活使用,一味追求三范式無疑會影響程序的性能,適當的冗余是可以提高查詢的效率的,前提要保證是主鍵的冗余。

  • 控制每張表的字段在20以內,否則業務分表

    數據表的寬度與內存占用的大小成正比,在進行讀寫操作時,數據庫程序將表結構與數據載入內存,當表寬度越長消耗的內存越多、越占IO流,導致操作的效率下降。將可能將字段按照業務細分、冷熱的條件進行分表設計。

字段設計規范

  • 盡可能不要在表中建立顧名思義的擴展字段

    比如ext、ext_1、extend_n,時間一長,好幾個這樣的字段,即使每一個都有comment,也會造成SQL的可讀性,特別是在構建SQL語句的時候。

  • 優先設置占存儲空間最小的類型和長度

    合理設置字段的類型和長度,可以節省MySQL的表空間,是性能優化的姿勢之一。同時,索引列定義空間越大也會導致建立索引的所需空間也越大。應當嚴禁定義字段,譬如

    IP應使用UNSUGNED或者INT結構類型,在PHP中可以使用long2ipip2long函數進行互轉

    性別應使用CHAR(1),即定長的字符串類型

    ... ...

  • 盡可能避免使用TEXTBLOBENUM數據類型

    MySQL 內存臨時表不支持TEXTBLOB這樣的大數據類型,如果查詢中包含這樣的數據,在排序等操作時,就不能使用內存臨時表,必須使用磁盤臨時表進行,毋庸置疑會降低查詢的效率。MySQL對索引字段長度是有限制的,TEXTBLOB類型只能使用前綴索引。

  • 避免ENUM數據類型

    MySQL中,存儲枚舉類型的數據在庫中,字段列中保存的值實際為整數,特別容易導致開發者混亂,同時在查詢使用排序是基于數值整型的,雖然可以使用ORDER BY FIELD(),但是會導致索引失效,盡量避免這么做。

  • 盡可能將所有的數據列定義為NOT NULL類型

    NULL列比較特殊,需要額外的空間來保存,同時會造成索引失效。

  • 使用TIMESTAMPINT替換DATETIME存儲時間

    很明顯,TIMESTAMPINT占4位字節,而DATETIME占8位字節。那么存儲時間應該如何選擇TIMESTAMPINT呢?TIMESTAMP的可讀性高而INT的靈活性高,因而經常需要使用計算操作的應當使用INT存儲,否則使用TIMESTAMP。

  • 金額相關的數據必須使用DECIMAL數據類型

    談到錢這個東西呢,精確是非常重要的,即便要浪費存儲空間、笑?~DECIMAL 類型為精準浮點數,在計算時不會丟失精度,可以自定義其長度,可用于存儲比 bigint 更大的整型數據。

  • 表與表關聯的鍵名保持一致或以關聯表名的縮寫為前綴

    規范事項,保持規范、養成習慣,提高程序的可讀性。

  • 固定長度的字符串字段務必使用CHAR

    節省存空間、降低內存使用率、提高讀寫性能。

  • 使用UNSIGNEG存儲非負整數

    節省存空間、降低內存使用率、提高讀寫性能。

  • 禁止敏感數據以明文形式存儲

    確保信息的安全性,比如密碼、隱秘數據等。

索引規范

  • 重要的SQL語句必須帶上索引作為條件

  • 避免冗余和重復索引

    重復索引: 在相同的列上按照相同的順序創建的相同類型的索引。

    冗余索引: 兩個索引按照相同的順序覆蓋了相同的列。

    在一張用戶表里面,將用戶id設置成主鍵的同時再設置成唯一索引,那就是重復索引,如果創建了索引(a,b),再設置a索引,則a為冗余索引,這兩種錯誤的操作都會降低讀寫的性能。

  • 務必不要在作為查詢條件很少、或者沒有關聯的字段下建立索引

    索引本身占用存儲空間,過多設置會導致查詢效率降低。比如在成績表中將分數設置為索引,這是一種錯誤的做法。

  • 禁止在索引列進行數學運算和函數運算

    MySQL不擅長于運算,需要計算的應該移至代碼業務層。總而言之,凡是計算都要移至代碼業務層(MySQL不擅長于運算)。

  • 符合索引將區分度高的置前

    將區分度高的索引置前可以縮短查詢的范圍,以至提高查詢的效率,特別是在JOIN連表查詢,提高效率特別明顯。

SQL使用規范

  • 危險的SQL語句必須帶上索引作為條件,謹記謹記

    哪些是危險的SQL語句呢,刪、改皆為危險的語句,一定要記住帶上WHERE。

  • 建議使用預編譯語句操作數據庫

    先簡單了解下SQL執行的流程,SQL先解析、預編譯處理再生成執行計劃,最后調用引擎的api方法返回執行的結果,使用預編譯的操作姿勢,在讀寫的時候可以省去預編譯的時間,終而提高執行效率。

  • 嚴禁使用SELECT *查詢字段

    要什么SELECT什么,不能多,否則可能導致覆蓋索引失效,消耗更多的 CPUIO 以網絡帶寬資源。

  • 查詢語句務必帶上索引以提高查詢效率

  • 必須避免數據類型隱式轉換

    MySQL中,數據會存在隱式轉換,當該字段發生轉換時,索引會造成失效。

  • 充分利用利用索引優勢

    既然設置了索引就好好充分利用好索引,將查詢的效率提至最高。

  • 禁止使用相同的賬號跨庫操作

    各執其職,互不越權。

  • 禁止使用帶有數據值卻不帶有字段鍵名的INSERT操作

    這是一種錯誤的做法,對于表的改動后會造成比較大的影響。

    INSERT INTO user VALUES ('alicfeng',23);
    # 應該這樣操作
    INSERT INTO user (`username`,`age`) VALUES ('alicfeng',23);
    
  • 盡可能使用JOIN替代子查詢操作

    子查詢的結果集無法使用索引,通常子查詢的結果集會被存儲到臨時表中,不論是內存臨時表還是磁盤臨時表都不會存在索引,所以查詢性能會受到一定的影響。 特別是對于返回結果集比較大的子查詢,其對查詢性能的影響也就越大。 由于子查詢會產生大量的臨時表也沒有索引,所以會消耗過多的 CPUIO 資源,產生大量的慢查詢。

  • 盡可能避免使用JOIN關聯過多的表

    一般情況下,建議JOIN的表不要超過5個,JOIN多表查詢比較耗時時間,關聯的表越多越耗時間,防止執行超時或死鎖。

  • 合并操作、減少數據庫的交互

    可以靈活地合并 SQL 操作,降低IO消耗的同時也提高了執行效率,譬如

    UPDATE user SET username='alicfeng' FROM id=1995;
    UPDATE user SET age=23 FROM id=1995;
    
    # 合并操作成一條SQL
    UPDATE user SET username='alicfeng',age=23 FROM id=1995;
    
  • 盡可能使用IN代替OR語句

  • 禁止使用ORDER BY RAND()隨機排序語句

    會把表中所有符合條件的數據裝載到內存中,然后在內存中對所有數據根據隨機生成的值進行排序,并且可能會對每一行都生成一個隨機值,如果滿足條件的數據集非常大,就會消耗大量的 CPUIO 及內存資源。

  • 禁止在WHERE語句中進行計算

    對列進行函數轉換或計算時會導致無法使用索引。

    # 索引會失效
    WHERE DATE(create_date)='20190308';
    # 靈活使用[推薦]
    WHERE create_date>='20190308' AND create_date<'20190309';
    
  • 使用UNION ALL而不是使用UNION

    在已知數據沒有重復或無須刪除重復行的前提下,因為UNION需要重復值掃描,降低效率。

  • 大批量寫操作盡可能合理地分批次處理

    大批量的操作應當合理平均分批次處理,防止死鎖影響業務,同時盡量將跑批這種大操作至于凌晨操作。

  • 不在數據庫做運算,務必將運算置于業務層

    MySQL不擅長數學運算和邏輯判斷。

  • 禁止使用索引做運算

    索引會失效。

  • SQL語句簡單化

  • 使用事務盡量簡單化,同時控制事務執行的時間

    時間長會導致長時間鎖表,造成死鎖,進而影響業務。

  • IN語句參數的個數盡量控制在1000以內

  • 注意LIMIT分頁查詢效率,LIMIT越大效率越低

    在使用LIMIT做分頁時,更改巧妙地處理查詢,譬如使用S1替換成S2,將有效地提高查詢的效率。

    # S1
    SELECT `username` FROM `user` LIMIT 10000,20;
    # S2
    SELECT `username` FROM `user` WHERE id>10000 LIMIT 20;
    
  • 編寫SQL語句必須全部為大寫,每個詞必只允許只有一個空格符

    編寫規范,必須統一并遵循。

  • 盡可能使用EXIST|NOT EXIST替代IN | NOT IN

  • 禁止使用LIKE添加%前綴進行模糊查詢

    %前置會導致索引失效

  • 禁止一條語句同時對多個表進行寫操作

參考A_aliane雪松等前輩的總結,非常感謝!

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,698評論 6 539
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,202評論 3 426
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,742評論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,580評論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,297評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,688評論 1 327
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,693評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,875評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,438評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,183評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,384評論 1 372
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,931評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,612評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,022評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,297評論 1 292
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,093評論 3 397
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,330評論 2 377

推薦閱讀更多精彩內容

  • Voting 投票 Every token holder can vote on a proposal by ca...
    orcl_zhang閱讀 656評論 0 51
  • 文/夏紫蟬 冬的窗口,路邊的野菊,依然開得妖嬈,那一抹顏色,明媚了蕭瑟的冬景,燦爛了略感落寞的心境。 紅塵深處,我...
    夏紫蟬閱讀 1,369評論 28 30
  • 醫院里病床上掛著點滴,治療室的蒙古(太美麗一直誤認為維吾爾)姐姐拿來半袋自家的奶酪,饞嘴的我取出一塊兒放入嘴中,自...
    元合閱讀 370評論 0 0