MySQL 資料庫設計規範 詳解
阿新 • • 發佈:2018-12-27
1> 資料庫涉及字元規範採用 26 個英文字母(區分大小寫) 和 0-9 這十個自然數,加上下劃線'_'組成,共 63 個字元,不能出現其他字元(註釋除外)注 : 1> 以上命名都不得超過 30 個字元的系統限制,變數名的長度限制為 29(不包括標識字元@) 2> 資料物件、變數的命名都採用英文字元,禁止使用中文命名。絕對不要在對象名的字元之間留空格 3> 小心保留詞,要保證欄位名沒有和保留詞、資料庫系統或者常用訪問方法衝突 4> 保持欄位名和型別的一致性,在命名欄位併為其指定資料型別的時候一定要保證一致性。假如資料型別在一個表裡是整數,那在另一個表裡可就別變成字 符型2> 資料庫命名規範資料庫名使用小寫英文以及下劃線組成,比如 : my_dbsnepr備份資料庫名使用正式庫名加上備份時間組成,如 : dbname_200704033> 資料庫表命名規範資料表名使用小寫英文以及下劃線組成,比如 : info_user system_destination資訊類採用 : info_xxx檔案類採用 : file_xxx關聯類採用 : inter_xxx備份資料表名使用正式表名加上備份時間組成,如 : info_user_20070403 system_destination_200704034> 欄位命名規範欄位名稱使用單詞組合完成,首字母小寫,後面單詞的首字母大寫,最好是帶 表名字首,如 web_user 表的欄位 : userId userName如果表名過長,可以取表名的前5個字母。如果表名為多個單詞組合,可以取前一個單詞,外加後續其它單詞的首字母作為欄位名表與表之間的相關聯欄位要用統一名稱,如 info_user 表裡面的 userId 和 group 表裡面的 userId 相對應業務流水號統一採用 : 表名_seq注 : 欄位名前面增加表名,就不用擔心在多表查詢時對同名欄位的衝突表名、欄位名必須使用小寫字母或數字;禁止出現數字開頭,禁止兩個下劃線中間只出現數字。資料庫欄位名的修改代價很大,因為無法進行預釋出,所以欄位名稱需要慎重考慮正例 : getter_admin, task_config, level3_name 反例 : GetterAdmin, taskConfig, level_3_name表達是與否概念的欄位,必須使用 is_xxx 的方式命名,資料型別是 unsigned tinyint(1 表示是, 0 表示否) ,此規則同樣適用於 odps 建表說明 : 任何欄位如果為非負數,必須是 unsigned表名不使用複數名詞說明 : 表名應該僅僅表示表裡面的實體內容,不應該表示實體數量,對應於 DO 類名也是單數形式,符合表達習慣唯一索引名為 uk_欄位名;普通索引名則為 idx_欄位名說明 : uk_ 即 unique key;idx_ 即 index 的簡稱小數型別為 decimal,禁止使用 float 和 double說明 : float 和 double 在儲存的時候,存在精度損失的問題,很可能在值的比較時,得到不正確的結果。如果儲存的資料範圍超過 decimal 的範圍,建議將資料拆成整數和小數分開儲存如果儲存的字串長度幾乎相等,使用 char 定長字串型別varchar 是可變長字串,不預先分配儲存空間,長度不要超過 5000,如果儲存長度大於此值,定義欄位型別為 text,獨立出來一張表,用主鍵來對應,避免影響其它欄位索引效率表必備三欄位 : id, gmt_create, gmt_modified說明 : 其中 id 必為主鍵,型別為 unsigned bigint、單表時自增、步長為 1。 gmt_create, gmt_modified 的型別均為 date_time 型別表的命名最好是加上“業務名稱_表的作用”正例: tiger_task / tiger_reader / mpp_config庫名與應用名稱儘量一致單錶行數超過 500 萬行或者單表容量超過 2GB,才推薦進行分庫分表說明 : 如果預計三年後的資料量根本達不到這個級別,請不要在建立表時就分庫分表5> 外來鍵命名規範外來鍵名稱為 FK_表名_A_表名_B_關聯欄位名其中表名和關聯欄位名如果過長,可以取表名、關聯欄位名的前5個字母如果表名、關聯欄位為多個單詞組合,可以取前一個單詞,外加後續其它單詞的首字母作為欄位名如 : FK_user_token_user_phnum;6> 欄位型別規範規則 : 用盡量少的儲存空間來存數一個欄位的資料 <1> 能用 int 的就不用 char 或者 varchar <2> 能用 varchar(20) 的就不用 varchar(255) <3> 時間戳欄位儘量用 int 型,如 created:表示從'1970-01-01 08:00:00'開始的 int 秒數,採用英文單詞的過去式;gmtCreated:表示 datetime 型別的時間,即形如'1980-01-01 00:00:00'的時間串,Java 中對應的型別為 Timestamp7> 索引使用原則 <1> 邏輯主鍵使用唯一的成組索引,對系統鍵 (作為儲存過程) 採用唯一的非成組索引,對任何外來鍵列採用非成組索引。考慮資料庫的空間有多大,表如何進行訪問,還有這些訪問是否主要用作讀寫 <2> 大多數資料庫都索引自動建立的主鍵欄位,但是可別忘了索引外來鍵,它們也是經常使用的鍵,比如執行查詢顯示主表和所有關聯表的某條記錄就用得上 <3> 不要索引 blob/text 等欄位,不要索引大型欄位(有很多字元),這樣作會讓索引佔用太多的儲存空間 <4> 不要索引常用的小型表 <5> 不要為小型資料表設定任何鍵,假如它們經常有插入和刪除操作就更別這樣做,對這些插入和刪除操作的索引維護可能比掃描表空間消耗更多的時間業務上具有唯一特性的欄位,即使是組合欄位,也必須建成唯一索引說明 : 不要以為唯一索引影響 insert 速度,這個速度損耗可以忽略,但提高查詢速度是明顯的;另外,即使在應用層做非常完善的校驗和控制,只要沒有唯一索引,根據墨菲定律,必然有髒資料產生超過三個表禁止 join。需要 join 的欄位,資料型別保持絕對一致; 多表關聯查詢時,保證被關聯的欄位需要有索引說明 : 即使雙表 join 也要注意表索引、SQL 效能在 varchar 欄位上建立索引時,必須指定索引長度,沒必要對全欄位建立索引,根據實際文字區分度決定索引長度說明 : 索引的長度與區分度是一對矛盾體,一般對字串型別資料,長度為 20 的索引,區分度會高達 90%以上,可以使用 count(distinct left(列名, 索引長度))/count(*) 的區分度來確定頁面搜尋嚴禁左模糊或者全模糊,如果需要請走搜尋引擎來解決說明 : 索引檔案具有 B-Tree 的最左字首匹配特性,如果左邊的值未確定,那麼無法使用此索引如果有 order by 的場景,請注意利用索引的有序性。 order by 最後的欄位是組合索引的一部分,並且放在索引組合順序的最後,避免出現 file_sort 的情況,影響查詢效能正例 : where a=? and b=? order by c; 索引 : a_b_c反例 : 索引中有範圍查詢,那麼索引有序性無法利用,如 : WHERE a>10 ORDER BY b; 索引a_b 無法排序先快速定位需要獲取的 id 段,然後再關聯 : SELECT a.* FROM 表 1 a, (select id from 表 1 where 條件 LIMIT 100000,20 ) b where a.id=b.id建組合索引的時候,區分度最高的在最左邊建立索引時避免有如下極端誤解 :1> 誤認為一個查詢就需要建一個索引2> 誤認為索引會消耗空間、嚴重拖慢更新和新增速度3> 誤認為唯一索引一律需要在應用層通過 "先查後插" 方式解決不要使用 count(列名)或 count(常量)來替代 count(*),count(*)就是 SQL92 定義的標準統計行數的語法,跟資料庫無關,跟 NULL 和 非NULL 無關說明 : count(*) 會統計值為 NULL 的行,而 count(列名)不會統計此列為 NULL 值的行count(distinct col) 計算該列除 NULL 之外的不重複數量注 : count(distinct col1, col2) 如果其中一列全為 NULL,那麼即使另一列有不同的值,也返回為 0當某一列的值全是 NULL 時,count(col)的返回結果為 0,但 sum(col)的返回結果為NULL,因此使用 sum()時需注意 NPE 問題正例 : 可以使用如下方式來避免 sum 的 NPE問題 : SELECT IF(ISNULL(SUM(g)),0,SUM(g)) FROM table;使用 ISNULL()來判斷是否為 NULL 值,說明 :1> NULL<>NULL 的返回結果是 NULL, 而不是 false2> NULL=NULL 的返回結果是 NULL, 而不是 true3> NULL<>1 的返回結果是 NULL,而不是 true注 : NULL 與任何值的直接比較都為 NULL在程式碼中寫分頁查詢邏輯時,若 count 為 0 應直接返回,避免執行後面的分頁語句不得使用外來鍵與級聯,一切外來鍵概念必須在應用層解決說明 : 學生表中的 student_id 是主鍵,那麼成績表中的 student_id 則為外來鍵。如果更新學生表中的 student_id,同時觸發成績表中的 student_id 更新,則為級聯更新。外來鍵與級聯更新適用於單機低併發,不適合分散式、高併發叢集;級聯更新是強阻塞,存在資料庫更新風暴的風險;外來鍵影響資料庫的插入速度禁止使用儲存過程,儲存過程難以除錯和擴充套件,更沒有移植性資料訂正時,刪除和修改記錄時,要先 select,避免出現誤刪除,確認無誤才能執行更新語句in 操作能避免則避免,若實在避免不了,需要仔細評估 in 後邊的集合元素數量,控制在 1000 個之內如果有全球化需要,所有的字元儲存與表示,均以 utf-8 編碼,那麼字元計數方法說明 :SELECT LENGTH("輕鬆工作"); 返回為 12SELECT CHARACTER_LENGTH("輕鬆工作"); 返回為 4如果要使用表情,那麼使用 utfmb4 來進行儲存,注意它與 utf-8 編碼的區別TRUNCATE TABLE 比 DELETE 速度快,且使用的系統和事務日誌資源少,但 TRUNCATE 無事務且不觸發 trigger,有可能造成事故,故不建議在開發程式碼中使用此語句說明 : TRUNCATE TABLE 在功能上與不帶 WHERE 子句的 DELETE 語句相同POJO 類的 boolean 屬性不能加 is,而資料庫欄位必須加 is_,要求在 resultMap 中進行欄位與屬性之間的對映說明 : 參見定義 POJO 類以及資料庫欄位定義規定,在 sql.xml 增加對映,是必須的不要用 resultClass 當返回引數,即使所有類屬性名與資料庫欄位一一對應,也需要定義; 反過來,每一個表也必然有一個與之對應說明 : 配置對映關係,使欄位與 DO 類解耦,方便維護8> SQL語句規範所有SQL關鍵詞全部大寫,比如 SELECT,UPDATE,FROM,ORDER,BY 等,表名與欄位名不需要大寫,如 :SELECT COUNT(*) FROM cdb_members WHERE userName='aeolus';在表查詢中,一律不要使用 * 作為查詢的欄位列表,需要哪些欄位必須明確寫明說明 : 1> 增加查詢分析器解析成本 2> 增減欄位容易與 resultMap 配置不一致不要寫一個大而全的資料更新介面,傳入為 POJO 類,不管是不是自己的目標更新字段,都進行 update table set c1=value1,c2=value2,c3=value3; 這是不對的。執行 SQL 時,儘量不要更新無改動的欄位,一是易出錯; 二是效率低; 三是 binlog 增加儲存9> 內容註釋儲存過程,觸發器,函式,檢視等都應該加上內容註釋,註釋格式如下:-- =============================================-- Author: Tiger-- Create date: 2009-4-15-- Description: 根據資訊完整度生成客戶統計資料-- Update: 2009-4-30 By Tiger-- =============================================表的陌生欄位應當加上簡要的欄位說明和內容說明10> 其他設計技巧 <1> 避免使用觸發器 : 觸發器的功能通常可以用其他方式實現,在除錯程式時觸發器可能成為干擾,假如確實需要採用觸發器,最好集中對它文件化 <2> 避免使用儲存過程 <3> 使用常用英語 (或者其他任何語言) 而不要使用拼音首字母縮寫 <4> 更新資料表記錄時,必須同時更新記錄對應的 gmt_modified 欄位值為當前時間