1. 程式人生 > >MySQL 設計與開發規範

MySQL 設計與開發規範

1 目的

      本規範的主要目的是希望規範資料庫設計與開發,儘量避免由於資料庫設計與開發不當而產生的麻煩;同時好的規範,在執行的時候可以培養出好的習慣,好的習慣是軟體質量的很好保證。

2 適用範圍

     本規劃的適用人員範圍包括涉及資料庫設計與開發的相關技術人員。

3 術語約定

    本規範採用以下術語描述:

★規則:也稱為強規範是程式設計時必須強制遵守的原則

★建議:程式設計時必須加以考慮的原則

★說明:對此規則或建議進行必要的解釋

★示例:對此規則或建議從正、反兩個方面給出

4 規範及建議

4.1 書寫規範

4.1.1 SQL書寫規範

規則1: 資料庫程式碼中,關鍵字大寫,其他內容小寫;

示例:

如下程式碼不符合規範:(關鍵字未大寫)

select last_name ,job_id

from employees;

如下程式碼符合規範:

SELECT last_name, job_id

FROM employees;

規則2:程式塊應採用縮排風格書寫,保證程式碼可讀,風格一致,縮排格數統一為4格;

規則3:程式碼中需要空位時,統一採用英文空格鍵輸入,不允許用TAB鍵 產生空位;

說明:不同的編輯器對TAB的空位格數設定不一致,會導致使用TAB鍵產生空位的程式碼格式混亂;

規則4:同一條語句佔用多行時,每一行的開始應是關鍵字, 且關鍵字應和第一行左對齊,如確實不能從關鍵字分行,則分行處應對其上一行被分行的同類程式碼的最左邊;

示例:

如下程式碼不符合規範(分行書寫時,其餘行未和第一行左對齊)

SELECT last_name,

job_id

FROM employees;

如下程式碼也不符合規範(分行時,不是從關鍵字分行)

SELECT last_name,

job_id FROM employees;

如下程式碼符合規範

SELECT last_name, job_id

FROM employees;

如下程式碼符合規範

SELECT last_name,

       first_name,

       job_id

FROM employees;

規則5:查詢資料時,儘量不使用SELECT *,而是給出明確的欄位,但該規則不包括SELECT COUNT(*)語 句;

示例

如下語句不符合規範(SELECT操作未給出欄位)

SELECT *

FROM employees;

如下語句符合規範

SELECT last_name, first_name

FROM employees;

規則6:INSERT語句應該給出欄位列表;

示例

如下語句不符合規範(INSERT操作未給出欄位名稱)

INSERT INTO employees

VALUES

(

    'GUO',

    'DAVID',

    100

);

如下語句符合規範

INSERT INTO employees

(

    last_name,

    first_name,

    job_id

)

VALUES

(

    'GUO',

    'DAVID',

    100

);

規則7:從表中同一筆記錄中獲取記錄的欄位值,須使用一SQL語句得到,不允許分多條SQL語句;

示例

如下語句不符合規範(從同一個表中取出記錄,分成兩條語句分別掃描)

UPDATE employees_new

SET last_name=

(

    SELECT last_name

    FROM employees

    WHERE job_id = 100

)

WHERE job_id = 100;

UPDATE employees_new

SET first_name =

(

    SELECT first_name

    FROM employees

    WHERE job_id = 100

)

WHERE job_id = 100;

如下語句符合規範

UPDATE employees_new

SET first_name =

(

    SELECT last_name

    FROM employees

    WHERE job_id = 100

),

last_name =

(

    SELECT first_name

    FROM employees

    WHERE job_id = 100

)

WHERE job_id = 100;

規則8:SQL語句中的逗號後面應增加一個空格,以使得程式碼清晰;

示例

如下程式碼不符合規範(逗號後面沒有空格)

SELECT last_name,job_id

FROM employees;

如下程式碼符合規則

SELECT last_name, job_id

FROM employees;

規則9:不允許將SQL語句寫成一行,再短的SQL也應該在謂詞處分行;

示例

如下程式碼不符合規範(未在謂詞部分進行分行)

SELECT last_name, job_id FROM employees WHERE job_id = 1;

如下程式碼符合規範

SELECT last_name, job_id

FROM employees

WHERE job_id = 1;

規則10:運算子以及比較符左邊或者右邊只要不是括號,則空一格;

示例

如下程式碼不符合規範(運算子沒有空格)

SELECT CURRENT_DATE+INTERVAL 1 DAY

FROM dual;

如下程式碼符合規範

SLEECT CURRENT_DATE + (INTERVAL 1 DAY)

FROM dual;

規則11:不同型別的操作符混合使用時,應使用括號明確的表達運算的先後關係;

示例

如下程式碼不符合規範(運算優先順序關係易混淆)

SELECT a*b/c+d*e

FROM dual;

如下程式碼符合規範

SELECT ((a * b) / c) + (d * e)

FROM dual;

規則12:任何SQL書寫單行不得超過120字元(含左邊的縮排);

建議1:對於INSERT…VALUES和UPDATE語句,一行寫一個欄位,每個欄位相對於INSERT語句空4格,欄位後面緊跟註釋(註釋語句左對齊),VALUES和INSERT左對齊,左括號和右括號與INSERT、VALUES左 對齊;

示例:

如下程式碼不符合建議(欄位未和INSERT語句空格)

INSERT INTO sm_user

(

user_id,   --使用者ID,主鍵

user_name, --使用者名稱

login_name --登入名

)

VALUES

(

p_user_id,

p_user_name,

p_login_name

);

如下程式碼符合建議

INSERT INTO sm_user

(

    user_id,   --使用者ID,主鍵

    user_name, --使用者名稱

    login_name --登入名

)

VALUES

(

    p_user_id,

    p_user_name,

    p_login_name

);

建議2:INSERT…SELECT 語句時,應使每行的欄位順序對應,以每行最多不超過4個欄位,以方便程式碼閱讀,括號的內容另起一行縮排4格開始書寫,關鍵字單詞左對齊,左括號、右括號另起一行與左對齊;

示例

如下程式碼不符合建議(欄位未和括號分行)

INSERT INTO sm_duty_bak(duty_id, duty_name, created_by, creation_date,

last_updated_by, last_update_date, disable_date)

SELECT duty_id, duty_name, created_by, creation_date,

last_updated_by, last_update_date, disable_date

FROM sm_duty

WHERE duty_id=88;

如下程式碼符合建議

INSERT INTO sm_duty_bak

(

    duty_id, duty_name, created_by, creation_date,

    last_updated_by, last_update_date, disable_date

)

SELECT

    duty_id, duty_name, created_by, creation_date,

    last_updated_by, last_update_date, disable_date

FROM sm_duty

WHERE duty_id = 88;

說明:

1.SELECT 語句中每行的欄位應與INSERT 語句對應。

2.INSERT 語句中換行的欄位名應縮排並與上一行的第一個欄位名對齊。

3.SELECT 語句中換行的欄位名應縮排並與上一行的第一個欄位名對齊。

4.1.2 儲存過程書寫規範

規則1:不允許將多行語句書寫在同一行;

示例

如下程式碼不符合規範(將兩行定義書寫在同一行)

SET v_count = 1; SET v_creation_date = CURRENT_DATE;

如下程式碼符合規範

SET v_count = 1;

SET v_creation_date = CURRENT_DATE;

規則2:相對獨立的程式塊之間應加空行;

示例

如下程式碼不符合規範(變數定義和程式段之間無空行)

SET v_duty_id = 1;

IF (v_disabled_date >  v_current_date) THEN

    SELECT duty_name

    into v_duty_name

    FROM sm_duty

    WHERE duty_id = :duty_id;

    …

END IF;

如下程式碼符合規範

SET v_duty_id = 1;

IF (v_disabled_date >  v_current_date) THEN

    SELECT duty_name

    into v_duty_name

    FROM sm_duty

    WHERE duty_id = :duty_id;

    …

END IF;

規則3:當一個SQL 語句中涉及到多個表時,始終使用別名來限定欄位名,這使其它人閱讀起來更方便,避免了含義模糊的引用,其中能夠通過別名清晰地判斷出表名;

說明 : 別名命名時,儘量避免使用無意義的代號a、b 、c… , 而應該有意義( 如表mtl_system_items_b 對應別名為msi,po_headers_all 別名對應為pha)。

示例

如下語句不符合規範(未使用有明確含義的表別名)

SELECT a.wip_entity_name, a.wip_entity_id, a.date_released

FROM wip.wip_entities b,

wip.wip_discrete_jobs a

WHERE b.wip_entity_id = a.wip_entity_id

AND a.status_type = 3

如下語句符合規範

SELECT wdj.we_entity_name, wdj.wip_entity_id, wdj.date_released

FROM wip.wip_entities we,

           wip.wip_discrete_jobs wdj

WHERE we.wip_entity_id = wdj.wip_entity_id

AND we.status_type = 3

規則4:確保變數/引數的型別和長度與表資料欄位的型別和長度相匹配;

說明:如果與表資料列寬度不匹配,則當較寬或較大的資料傳進來時會產生執行異常。

示例

如下程式碼不符合規範(假定表wap_user的欄位user_name的定義為VARCHAR(10))

CREATE PROCEDURE ps_add()

BEGIN

      DECLARE v_user_name VARCHAR(15); 

      UPDATE wap_user

      SET user_name = v_user_name

      WHERE sky_id = 100;

END;

如下程式碼符合規範

CREATE PROCEDURE ps_add()

BEGIN

      DECLARE v_user_name VARCHAR(10); 

      UPDATE wap_user

      SET user_name = v_user_name

      WHERE sky_id = 100;

END;

規則5:儲存過程程式碼塊必須有註釋;

建議1:減少控制語句的判斷次數,比如在ELSE(IF…ELSE) 語句中,儘量將盡快能檢測到結果的判斷放在前面;

示例

如下語句不符合規範(假定v_count=1的條件大多數情況會滿足)

IF (v_count = 0) THEN

    NULL;

ELSEIF (v_count = 1) THEN

    NULL;

END IF;

如下語句符合規範(假定v_count=1的條件大多數情況會滿足)

IF (v_count = 1) THEN

    NULL;

ELSEIF (v_count = 0) THEN

    NULL;

END IF;

建議2:儘量避免使用巢狀的IF語句,在這種情況下應使用多個IF語句來判斷其可能性;

示例

如下語句不符合規範(使用了巢狀的IF語句來進行判定)

IF v_count = 0 THEN

    IF v_flag = 0 THEN

        NULL;

    ELSE

        NULL;

    END IF;

ELSE v_count = 1 THEN

    IF v_flag = 0 THEN

        NULL;

    ELSE

        NULL;

    END IF;

END IF;

如下語句符合規範

IF (v_count = 0) AND (v_flag = 0) THEN

    NULL;

ELSEIF (v_count = 0 ) AND (v_flag = 1) THEN

    NULL;

ELSEIF (v_count = 1) AND (v_flag = 0) THEN

    NULL;

ELSEIF (v_count = 1) AND (v_flag = 1) THEN

    NULL;

END IF;

建議3:儲存過程、函式、觸發器、程式塊中定義的變數和輸入、輸出引數在命名上有所區分;

說明:

用'v_ '開頭代表程式塊中定義的普通變數。

用'p_ '開頭代表輸入引數變數。

用'x_ '開頭代表輸入輸出或輸出引數變數。

用'cur_'開頭代表遊標變數。存放遊標記錄集。

4.2 物件命名規範

4.2.1 通用規則

規則1:任何資料庫物件的命名,不得使用漢字;

示例

如下語句不符合規範(表明和欄位名使用了漢字)

CREATE TABLE 使用者

(

    使用者名稱 VARCHAR(100),

    pass_word VARCHAR(16)

);

如下語句符合規範

CREATE TABLE wap_user

(

    user_name VARCHAR(100),

    pass_word VARCHAR(16)

);

規則2:庫名,表名,欄位名不得超過30個字元,使用者名稱不得超過16個字元;

庫名,表名,欄位名最多支援64個字元,為了統一規範、易於辨識以及減少傳輸量,必須不超過30個字元。

示例

如下語句不符合規範(表命名達到65位長度)(修改)

CREATE TABLE wap_user_tel_number_region_user

(

    user_name VARCHAR(100),

    pass_word VARCHAR(16)

);

如下語句符合規範

CREATE TABLE wap_user_tel_number_region

(

    user_name VARCHAR(100),

    pass_word VARCHAR(16)

);

規則3:使用者物件命名應全部為小寫,使用下劃線“_”分割;

說明:由於linux作業系統上的檔名是區分大小寫的,所以MySQL表名是區分大小寫的。

示例

如下語句不符合規範(表名應全部為小寫)

CREATE TABLE Wap_user_tel_number_region

(

    user_name VARCHAR(100),

    pass_word VARCHAR(16)

);

如下語句符合規範

CREATE TABLE wap_user_tel_number_region

(

    user_name VARCHAR(100),

    pass_word VARCHAR(16)

);

規則4:命名應使用富有意義的英文,禁止使用拼音首字母, 一般情況下不建議使用拼音命名;

示例

如下語句不符合規範(表名使用了中文且欄位使用了拼音首字母簡寫)

CREATE TABLE wap_yonghu

(

    yhm VARCHAR(100),

    pass_word VARCHAR(16)

);

如下語句符合規範

CREATE TABLE wap_user

(

    user_name VARCHAR(100),

    pass_word VARCHAR(16)

);

規則5:命名不得使用資料庫保留字;

說明:使用了資料庫保留字,會導致需要訪問該物件時,需要程式碼做特別的轉換才能訪問

示例

如下程式碼不符合規範(假定user為資料庫保留字)

CREATE TABLE wap_user

(

    USER VARCHAR(100),

    pass_word VARCHAR(16)

);

如下程式碼符合規範

CREATE TABLE wap_user

(

    user_name VARCHAR(100),

    pass_word VARCHAR(16)

);

4.2.2 表

規則1:同類業務的表,以相同的表示該類業務的英文開頭;

說明:同類業務的表以相同的英文開頭,在邏輯上清晰,且可避免維護過程中對該類表的誤操作

示例

如下語句不符合規範(假定表wap_user和表user_login_log都屬於wap類業務)

CREATE TABLE wap_user

(

    user_name VARCHAR(100),

    pass_word VARCHAR(16)

);

CREATE TABLE user_login_log

(

    user_name VARCHAR(100),

    login_date DATE

);

如下語句符合規範

CREATE TABLE wap_user

(

    user_name VARCHAR(100),

    pass_word VARCHAR(16)

);

CREATE TABLE wap_user_login_log

(

    user_name VARCHAR(100),

    login_date DATE

);

說明:各子系統不用加子系統名稱字首,如POS系統的表不用都加pos_字首,如果遇到需要同步其他系統的表的表名與本系統的表名相同時,用子系統名稱做字尾的形式重新命名其他子系統表名,如POS系統需要同步MDM表bill_item_dtl而POS系統也存在這樣的表名,則把MDM的表名重新命名為bill_item_dtl_mdm。

規則2:同類表,如果按照時間不同建立的表,字尾格式一般情況下應為’_YYYY[MM[DD]]’格式;

示例

如下語句不符合規範(將年份2010簡寫為10,導致含義模糊)

CREATE TABLE wap_user_login_1004

(

    user_name VARCHAR(100),

    login_date date

);

CREATE TABLE wap_user_login_1005

(

    user_name VARCHAR(100),

    login_date DATE

);

如下語句符合規範

CREATE TABLE wap_user_login_201004

(

    user_name VARCHAR(100),

    login_date DATE

);

CREATE TABLE wap_user_login_201005

(

    user_name VARCHAR(100),

    login_date DATE

);

4.2.3 欄位

規則1:欄位命名應具有含義,能反映該欄位儲存的內容,且欄位應增加欄位備註;

示例

如下語句不符合規範(假定儲存的欄位為使用者名稱和密碼,如下的欄位名毫無意義也沒有備註)

CREATE TABLE wap_user

(

    col1 VARCHAR(100),

    col2 VARCHAR(16)

);

如下語句符合規範

CREATE TABLE wap_user

(

    user_name VARCHAR(100),

    pass_word VARCHAR(16)

);

如下語句是使用了無意義欄位名,但增加了欄位說明,不作為推薦方法,但確實欄位名無法表述含義時,必須使用該方法;

CREATE TABLE wap_user

(

    col1 VARCHAR(100) comment 'username',

    pass_word VARCHAR(16) comment 'password'

);

規則2:同種用途的欄位,在所有表中,應保持有同樣的欄位型別和欄位長度,並儘量保持一致的欄位命名;

示例

如下語句不符合規範(欄位user_name在兩個有業務關係的表中欄位長度不一致,易導致業務介面衝突)

CREATE TABLE wap_user

(

    user_name VARCHAR(100),

    pass_word VARCHAR(16)

);

CREATE TABLE wap_user_login_log

(

    user_name VARCHAR(80),

    login_date DATE

);

如下語句符合規範

CREATE TABLE wap_user

(

    user_name VARCHAR(100),

    pass_word VARCHAR2(16)

);

CREATE TABLE wap_user_login_log

(

    user_name VARCHAR(100),

    login_date DATE

);

以下是建議的公共欄位名稱及型別

create_user

VARCHAR(32)

建檔人

create_time

datetime

建立時間

update_user

VARCHAR(32)

更新人

update_time

datetime

更新時間

remark

VARCHAR(255)

備註

contact_name

VARCHAR(32)

聯絡人

tel

VARCHAR(20)

電話號碼

mob

VARCHAR(20)

手機號碼

address

VARCHAR(100)

聯絡地址

zip_code

VARCHAR(10)

郵編

identity_card

VARCHAR(25)

身份證號

fax

VARCHAR(20)

傳真

email

VARCHAR(64)

電郵

建議1:   欄位名建議不要用JAVA關鍵字來命名,;

4.2.4 主鍵

規則1:涉及到要做分庫分表的表用有序UUID做主鍵,UUID主鍵型別選擇CHAR(32);

規則2:不涉及分庫分表的表選用自增長ID做主鍵,主鍵型別使用unsigned int或unsigned big int;

規則3:主鍵無特別要求的,欄位名統一定義為 id;

4.2.4 外來鍵

規則1:外來鍵名應以”fk_”開頭,後接表名;

示例

如下語句不符合規範(外來鍵名未以fk_開頭)

alter table wap_user_login_log

add constraint wap_user_login_log_f foreign key(user_name) REFERENCES tb_user_name(user_name)

如下語句符合規範

ALTER TABLE wap_user_login_log

ADD CONSTRAINT fk_wap_user_login_log FOREIGN KEY(user_name) REFERENCES tb_user_name(user_name)

規則2:不同的表的外來鍵,如果引用的是相同表的相同欄位,則外來鍵欄位名及型別應保持一致;

4.2.5 索引

規則1:唯一索引應以”uk_”+”表名_”+”欄位名”命名;

示例

如下語句不符合規範(唯一索引未以uk_開頭)

ALTER TABLE wap_user

ADD UNIQUE wap_user_username_u (username)

如下語句符合規範

 ALTER TABLE wap_user

 ADD UNIQUE uk_wap_user_username (username)

規則2:普通索引應以”idx_”+”表名_”+“欄位名”命名;

示例

如下語句不符合規範(不符合索引命名規範)

ALTER TABLE wap_user

ADD INDEX wap_user_user_id_idx (user_id)

如下語句符合規範

ALTER TABLE wap_user

ADD INDEX idx_wap_user_user_id (user_id)

規則3:全文索引索引應以”fullidx_”+”表名_”+“欄位名”命名;

4.2.6 檢視

規則1:檢視命名應以“v_”+“表名[_表名[_表名]]”命名,如果表名過多可以用“v_”+“功能描述”來命名;

示例

如下語句不符合規範(檢視和表是不可以同名的,如下語句會引起錯誤且不符合規範)

CREATE VIEW wap_user

AS

SELECT first_name, last_name, job_id

FROM wap_user;

如下語句符合規範

CREATE VIEW v_wap_user

AS

SELECT first_name, last_name, job_id

FROM wap_user;

4.2.7 函式

規則1:函式命名以”func_”開頭,後接函式的功能;

示例

如下語句不符合規範(未以func_開頭)

CREATE FUNCTION get_money

BEGIN

……

END;

如下語句符合規範

CREATE FUNCTION func_get_money

BEGIN

……

END;

4.2.8 儲存過程

規則1:儲存過程以“proc_”開頭,後接功能描述;

示例

如下語句不符合規範(未以proc_開頭)

CREATE PROCEDURE update_user

BEGIN

……

END;

如下語句符合規範

CREATE PROCEDURE proc_update_user

BEGIN

……

END;

4.2.9 觸發器

規則1:觸發器以“trig_”+表名+“_ins/del/upd”+”_before/after”命名;

示例

如下語句不符合規範(未遵循命名規範)

CREATE TRIGGER trigger1

AFTER DELETE ON wap_user

BEGIN

……

END;

如下語句符合規範

CREATE TRIGGER trig_wap_user_del_after

AFTER DELETE ON wap_user

BEGIN

……

END;

4.2.10 臨時表

規則1:臨時表以“tmp_”開頭,後接功能描述;

示例

如下語句不符合規範

CREATE TEMPORARY TABLE tab_tmp1

(

user_name VARCHAR(100),

pass_word VARCHAR(16)

);

如下語句符合規範

CREATE TEMPORARY TABLE tmp_wap_user

(

user_name VARCHAR(100),

pass_word VARCHAR(16)

);

規則2:如果是在上線/割接中被重新命名的表,命名應是原表名+“_YYYYMMDD”;

示例

如下語句不符合規範(臨時表以old結尾,而非日期結尾)

RENAME TABLE wap_user TO wap_user_old;

如下語句符合規範

RENAME TABLE wap_user TO wap_user_20100416;

4.2.11 使用者及資料庫名

規則1: 資料庫名:retail_字首+模組名,如POS系統的資料庫名為retail_pos,MDM的資料庫名為retail_mdm,使用者名稱與資料庫名儘量一致;

示例

如下語句符合規範

retail_pos    pos系統

retail_mps    營促銷系統

retail_oc      訂單中心

retail_pms    採購管理系統

retail_mdm    mdm

retail_gms    貨品管理系統

retail_fms    財務管理系統

4.3物件設計規範

4.3.1 表設計

規則1:資料庫設計文件中,必須包含表資料保留時間;

規則2:資料庫設計文件中,必須包含表在最大保留時間下的資料量;

規則3:資料庫設計文件中,必須包含表的讀寫頻率;

規則4:和其他表有關聯的表,和其他表功能一致的欄位型別以及長度,儘量使用相同的列名;

規則5: 每個表應設計一個主鍵;

規則6:資料庫字符集,表字符集,欄位字符集統一選用UTF8字符集,校對規則統一使用大小寫敏感的utf8_bin;

規則7:表引擎選用INNODB引擎;

規則8:必須要有表的註釋,用於描述表的功能;

建議1:對於需要同步到資料倉庫的表,原則上必須包含同步頻率以及同步機制;

建議2:歷史表字尾建議用“_hist”;

4.3.2 欄位

規則1:欄位必須要有註釋資訊,如果欄位的值是有限的(如狀態值只有“有效”、“無效”,如性別只有“男”、“女”等)必須在欄位註釋中對每個值表達的意思進行描述;

規則2:定長字元列使用CHAR型別, 不定長字元型使用VARCHAR型別;

規則3:日期欄位只需要表達年月日的選用DATE型別,需要表達年月日時分秒的欄位選用DATETIME類或TIMESTAMP型別,但請注意各自能表達的範圍以及TIMESTAMP的時區特性;

說明:MySQL中的DATETIME對應ORACLE的DATE型別,而MySQL的DATE型別只是ORACLE DATE型別的年月日部分不包括時分秒部分,MySQL TIME型別是ORACLE DATE 型別的時分秒部分,下表是MySQL各時間型別的格式樣例

Data Type

“Zero” Value

DATE

'0000-00-00'

TIME

'00:00:00'

'0000-00-00 00:00:00'

'0000-00-00 00:00:00'

YEAR

0000

DATETIME與TIMESTAMP型別的區別

DATETIME

TIMESTAMP

儲存長度

8位元組

4位元組

時區支援

不支援

支援

表達範圍

1000-01-01 00:00:00 

9999-12-31 23:59:59

1970-01-01 00:00:01

2038-01-19 03:14:07

儲存格式

實際格式儲存

UTC格式

規則4:ORACLE轉MySQL之NUMBER欄位型別轉換;

number(M,N)如果N是0則為整形,對應MySQL的整形型別,下面是MySQL的各整形型別的所需位元組數及能表達的範圍(摘抄至官網5.6),

Type

Storage

Minimum Value

Maximum Value

(Bytes)

(Signed/Unsigned)

(Signed/Unsigned)

TINYINT

1

-128

127

0

255

SMALLINT

2

-32768

32767

0

65535

MEDIUMINT

3

-8388608

8388607

0