本規範的主要目的是但願規範數據庫設計與開發,儘可能避免因爲數據庫設計與開發不當而產生的麻煩;同時好的規範,在執行的時候能夠培養出好的習慣,好的習慣是軟件質量的很好保證。html
本規劃的適用人員範圍包括涉及數據庫設計與開發的相關技術人員。mysql
本規範採用如下術語描述:linux
★規則:也稱爲強規範是編程時必須強制遵照的原則sql
★建議:編程時必須加以考慮的原則數據庫
★說明:對此規則或建議進行必要的解釋編程
★示例:對此規則或建議從正、反兩個方面給出數組
規則1: 數據庫代碼中,關鍵字大寫,其餘內容小寫;併發
示例:oracle
以下代碼不符合規範:(關鍵字未大寫)數據庫設計
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 語句中換行的字段名應縮進並與上一行的第一個字段名對齊。
規則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_'開頭表明遊標變量。存放遊標記錄集。
規則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)
);
規則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
);
規則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) |
傳真 |
|
VARCHAR(64) |
電郵 |
建議1: 字段名建議不要用JAVA關鍵字來命名,;
規則1:涉及到要作分庫分表的表用有序UUID作主鍵,UUID主鍵類型選擇CHAR(32);
規則2:不涉及分庫分表的表選用自增加ID作主鍵,主鍵類型使用unsigned int或unsigned big int;
規則3:主鍵無特別要求的,字段名統必定義爲 id;
規則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:不一樣的表的外鍵,若是引用的是相同表的相同字段,則外鍵字段名及類型應保持一致;
規則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_」+」表名_」+「字段名」命名;
規則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;
規則1:函數命名以」func_」開頭,後接函數的功能;
示例
以下語句不符合規範(未以func_開頭)
CREATE FUNCTION get_money
BEGIN
……
END;
以下語句符合規範
CREATE FUNCTION func_get_money
BEGIN
……
END;
規則1:存儲過程以「proc_」開頭,後接功能描述;
示例
以下語句不符合規範(未以proc_開頭)
CREATE PROCEDURE update_user
BEGIN
……
END;
以下語句符合規範
CREATE PROCEDURE proc_update_user
BEGIN
……
END;
規則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;
規則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;
規則1: 數據庫名:retail_前綴+模塊名,如POS系統的數據庫名爲retail_pos,MDM的數據庫名爲retail_mdm,用戶名與數據庫名儘可能一致;
示例
以下語句符合規範
retail_pos pos系統
retail_mps 營促銷系統
retail_oc 訂單中心
retail_pms 採購管理系統
retail_mdm mdm
retail_gms 貨品管理系統
retail_fms 財務管理系統
規則1:數據庫設計文檔中,必須包含表數據保留時間;
規則2:數據庫設計文檔中,必須包含表在最大保留時間下的數據量;
規則3:數據庫設計文檔中,必須包含表的讀寫頻率;
規則4:和其餘表有關聯的表,和其餘表功能一致的字段類型以及長度,儘可能使用相同的列名;
規則5: 每一個表應設計一個主鍵;
規則6:數據庫字符集,表字符集,字段字符集統一選用UTF8字符集,校對規則統一使用大小寫敏感的utf8_bin;
規則7:表引擎選用INNODB引擎;
規則8:必需要有表的註釋,用於描述表的功能;
建議1:對於須要同步到數據倉庫的表,原則上必須包含同步頻率以及同步機制;
建議2:歷史表後綴建議用「_hist」;
規則1:字段必需要有註釋信息,若是字段的值是有限的(如狀態值只有「有效」、「無效」,如性別只有「男」、「女」等)必須在字段註釋中對每一個值表達的意思進行描述;
規則2:定長字符列使用CHAR類型, 不定長字符型使用VARCHAR類型;
規則3:日期字段只須要表達年月日的選用DATE類型,須要表達年月日時分秒的字段選用DATETIME類或TIMESTAMP類型,但請注意各自能表達的範圍以及TIMESTAMP的時區特性;
說明:MySQL中的DATETIME對應ORACLE的DATE類型,而MySQL的DATE類型只是ORACLE DATE類型的年月日部分不包括時分秒部分,MySQL TIME類型是ORACLE DATE 類型的時分秒部分,下表是MySQL各時間類型的格式樣例
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 |
16777215 |
INT |
4 |
-2147483648 |
2147483647 |
|
|
0 |
4294967295 |
BIGINT |
8 |
-9223372036854775808 |
9223372036854775807 |
|
|
0 |
18446744073709551615 |
若是number(M,N)中N大於0則對應MySQL的decimal類型,如oracle的number(5,2)則MySQL爲decimal(5,2),值得注意的是,在超出範圍的狀況下ORACLE會報錯,而MySQL會取它能表示的最大值來替代原來的值,如decimal(5,2)/number(5,2)能表達的範圍爲 -999.99-999.99 若是要插入1000的數據,oracle會提示超表達範圍的錯,而MySQL會以999.99來替代
規則5:固定長度的字符串使用CHAR,單字符字段使用CHAR(1)類型;
規則6:字段避免使用NULL值,用默認值來替代,修改時間,審覈時間等用「0000-00-00 00:00:00」這樣的默認值進行替代,備註用‘’的空字符進替代;
規則7:不建議使用ENUM,SET類型,用TINYINT替代;
建議1: 儘可能不使用BLOB,TEXT類型,大字段建議單獨設計表,經過關聯進行查找;
建議2: 建議使用UNSIGNED 存儲非負數值;
一樣的字節數,存儲的數值範圍更大
規則1: 無特別說明,每一個表的索引不得超過5個;
規則2: 單字段上的索引不得超過2個;(即一個單字段最多可在上面創建一個單字段索引和一個組合索引包含這個字段)
規則3: 複合索引原則上不得超過3個字段;
規則4: 外鍵列須要建立索引;
建議1: 頻繁出如今where子句裏的字段建議創建索引;
建議2: 用來和其餘表關聯的字段建議創建索引;
建議3: 索引字段建議有高的選擇性和過濾性(count(distinct)/count(*)>0.6);
建議4: 創建索引的時候,建議考慮到SELECT和INSERT,UPDATE,DELETE的平衡;
建議5: 通常建議在查詢數據量10%如下使用索引;
建議6: WHERE子句的查詢條件構成索引字段前導字段;
建議7: 選擇性更高的字段放在組合字段索引的前導字段;
建議8: 若是字段選擇性接近,則把頻繁查詢的字段放在前面;
建議9: 進行GROUP BY或者是ORDER BY的字段應在組合字段索引的前導字段;
規則1:視圖中不容許出現ORDER BY排序;
規則2:基於多表關聯的視圖,必須在字段名前指定表別名;
建議1:視圖的基礎數據儘可能從表中獲取,儘可能不要嵌套視圖;
規則1: 避免將業務邏輯放在存儲過程當中,那樣容易將業務邏輯和DB耦合在一塊兒;
規則2: 存儲過程,必須有異常捕獲代碼;
規則3: 存儲過程當中嚴禁使用GOTO語句進行跳轉;
規則4: 有循環更新的存儲過程,必須進行批量提交,且必須進行事務控制;
說明:MySQL存儲過程當中必須用START TRANSACTION 來顯示開始一個事務,不然會按默認的每一個DML作個一個事務。
規則5: 存儲過程當中若是使用了遊標,則在存儲過程正常或者異常退出必須關閉全部打開的遊標;
規則6: 存儲過程當中若是有更新,必須在異常捕獲代碼中作回退操做;
規則7: 註釋格式以下,存儲過程說明放在在COMMENT中,其餘用」##」進行註釋說明;
CREATE PROCEDURE prc_vendor
COMMENT '說明:同步下發接收; 參數:xxxx; 返回:標誌0=成功;’
##創建:xxx 2012.07.17
## Modify by xxx 2012.08.08 增長供應商狀態字段
##Modify by xxx 2012.11.10 增長供應商英文名稱字段
BEGIN
...
END;
建議1:存儲過程每次被更新,應在註釋中說明更新的內容,更新的日期,以及更新的責任人,而且在更新前保留舊版本代碼
建議2:儘可能避免在存儲過程當中使用動態SQL。
規則1: 避免將業務邏輯放在函數中,那樣容易將業務邏輯和DB耦合在一塊兒;
規則2: 函數中,若是進行了事務處理,必須有異常捕獲代碼;
規則3: 函數中嚴禁使用GOTO語句進行跳轉;
規則4: 有循環更新的函數,必須進行批量提交,且必須進行事務控制;
規則5: 函數中若是使用了遊標,則在函數正常或者異常退出必須關閉全部打開的遊標;
規則6: 函數中若是對數據進行了更新操做,必須在異常捕獲代碼中作回退操做;
規則7: 註釋格式以下
CREATE FUNCTION func_get_serialno
(
p_request VARCHAR ###請求編號
)
return VARCHAR
COMMENT ’說明:產生序列號函數,經過serialno_config配置表響應產生序列號; 參數:p_requestid 請求編號 返回:返回須要的序列號‘
##創建:xxx 2013.07.02
##modified by xxx 2014-6-18 xxx
BEGIN
...
END;
建議1:函數每次被更新,應在註釋中說明更新的內容,更新的日期,以及更新的責任人,而且在更新前保留舊版本代碼;
建議2:函數儘可能只是實現複雜的計算功能,不對數據庫進行更新操做;
規範1:如無必要,不得設計觸發器,任何觸發器的設計,必須獲得DBA批准;
規範2:應用的完整性不該由觸發器保證,而是經過代碼的事務控制;
建議1:有高度一致性依賴的邏輯,觸發器應設計爲BEFORE而非AFTER方式;
規則1: 避免使用存儲過程、觸發器、函數等,容易將業務邏輯和DB耦合在一塊兒,而且MySQL的存儲過程、觸發器、函數中存在必定的BUG;
規則2: 禁止進行字段數據類型的隱式轉換,全部轉換必須進行明確的數據類型轉換;
說明:隱式轉換會致使字段上的索引失效, 最爲常見的隱式類型轉換常見於時間類型與字符串類型之間,建議全部時間類型字段在myBatis中均以時間類型傳入,或者以字符串傳入而後經過時間函數轉換字符串爲合法的時間格式 ,以下:
SELECT name
FROM member
WHERE vgmt_create=DATE_FORMATE('2009010101:02:03','%Y-%m-%d %H:%i:%s');
規則3: 禁止在多表關聯的時候,在非索引字段上的關聯;
規則4: 進行模糊查詢時,禁止條件中字符串直接以「%」開頭;
規則5: 在使用for update子句時必定注意限制條件,避免鎖定全表或者不須要被鎖定的行記錄。如無必要鎖定數據則應避免使用for update;
規則6: 在進行結果集合並(union或union all)時, 如不須要進行結果去重,則必須使用union all,而不能使用union;且儘可能減小進行數據集的去重;
規則7: 除非必要,避免使用 != 等非等值操做符,會致使用不到索引;
規則8: 禁止在 WHERE 條件中出現的過濾字段上使用任何函數進行類型或格式的轉換;正確的作法是把傳入的值轉換爲列類型所須要的;
錯誤的寫法:
SELECT username
FROM gl_user
WHERE DATE_FORMAT(gmt_create, %Y%m%d%H%i%s')='20090501022300‘;
正確的寫法:
SELECT username
FROM gl_user
WHERE gmt_create=DATE_FORMAT('20090501022300', '%Y-%m-%d %H:%i:s');
規則9: 禁止使用order by rand();
order by rand() 會將數據從磁盤中讀取,進行排序,會消耗大量的IO和CPU。
規則10:避免大使用大SQL,能夠拆分紅多個小SQL來替代;
規則1: 應用端全部查詢的 where 條件中的變量,都須要使用綁定變量來實現,以防SQL注入,同時性能也會更優;
規則2: 在 myBatis 的 SqlMap 文件中綁定變量使用 "#{var_name}"表示,替代變量使用"${var_name}";全部須要動態 Order By 條件的查詢,在使用替代變量過程當中,須要將可能傳入的內容以枚舉類寫死在代碼中,禁止接受任何外部傳入內容;對於不變的常量條件,請使用常量而不是變量;
規則3: IN子句,使用"Iterate + 數組類型變量"的方式實現綁定變量而不是經過代碼拼接 Query 語句;
例如:
myBatis會生成user_level in (1,2,3,4,5 ...)的語句
假若有相似下面分頁語句:
SELECT * FROM table ORDER BY create_time DESC LIMIT 10000,10;
這種分頁方式會致使大量的IO,由於MySQL使用的是提早讀取策略。
推薦分頁方式:
SELECT * FROM table WEHRE create_time < last_time ORDER BY create_time DESC LIMIT 10;
SELECT * FROM table INNER JOIN (SELECT id FROM table ORDER BY create_time LIMIT 10000,10) AS t USING(id);
建議1: 儘可能使用if來簡化SQL訪問數據庫的次數;
示例:
以下兩個語句實現的功能
SELECT COUNT(*) , SUM(salary)
FROM employees
WHERE department_id = 20
AND first_name LIKE 'SMITH%';
SELECT COUNT(*) , SUM(salary)
FROM employees
WHERE department_id = 30
AND first_name LIKE 'SMITH%';
可使用IF改寫爲以下語句
SELECT COUNT(IF(department_id=20, '*', NULL)) d20_count,
COUNT(IF(department_id=30, '*', NULL)) d30_count,
SUM(IF(department_id=20, salary, NULL)) d20_sal,
SUM(IF(department_id=30, salary, NULL)) d30_sal
FROM employees
WHERE first_name LIKE 'SMITH%';
建議2: 避免使用HAVING子句, HAVING 只會在檢索出全部記錄以後纔對結果集進行過濾. 這個處理須要排序,總計等操做. 若是能經過WHERE子句限制記錄的數目,那就能減小這方面的開銷;
示例
以下語句使用的是HAVING子句
SELECT last_name, avg(salary)
FROM employees
GROUP BY last_name
HAVING last_name != 'Grant'
AND last_name != 'Fay'
改寫使用WHERE的語句以下
SELECT last_name, avg(salary)
FROM employees
WHERE last_name != 'Grant'
AND last_name != 'Fay'
GROUP BY last_name
建議3: 儘可能少用not exist/no in等反向寫法。若是必定要用時,儘可能選擇not exist;
建議4: 儘可能少用is null/is not null等null的處理;
建議5: SQL語句中IN子句裏的值不該超過300;
建議6: 對於大表查詢中的列項應儘可能避免進行諸如CAST()或CONVERT()的轉換;
建議7: 儘可能避免進行全表掃描,限制條件儘量多,以便更快搜索到要查詢的數據;
建議8: SELECT查詢語句建議增長limit 1000 限定返回的行數;
建議9: 進行數據庫結構設計的時候,考慮適當的冗餘,儘可能確保應用讀寫數據的SQL簡潔;
建議10: 要返回MySQL自增序列的ID值,能夠考慮使用函數LAST_INSERT_ID(),此函數只能返回同
一個SESSION最近一次對有AUTO_INCREMENT屬性表INSERT的ID值
MySQL中此兩類字符串定義時候填寫的長度N,不是字節數的意思 ,而是字符數的意思。
咱們MySQL全部數據庫的字符集都爲UTF8,字符集校對規則爲UTF8_bin。對於中文漢字,實際存儲的時候佔三個字節,而數據或字母,則只佔一個字節。例如:
CREATE TABEL company_inventory (color VARCHAR(44) COMMENT '顏色');
則color最多能存儲40個字符。
獲取當前時間:NOW(),CURDATE()、CURTIME()
其中, NOW()函數精確到秒, 格式:YYYY-MM-DD HH:MM:SS
CURDATE函數精確到天,格式:YYYY-MM-DD
CURTIME函數精確到秒,格式:HH:MM:SS
日期數值的加減函數:
DATE_ADD(date,INTERVAL expr type)
DATE_ SUB(date,INTERVAL expr type)
經常使用的幾種type類型:YEAR、MONTH、DAY、HOUR、MINUTE,其中expr能夠爲正數或負數,咱們在開過程當中,通常使用DATE_ADD()函數,若要做日期減去一個數字的方式,就使用負數。
DATEDIFF(expr1,expr2),是返回 開始日期expr1與 結束日期expr2之間,相差的天數 ,返回值爲正數或負數。
返回日期某部分信息的函數:
YEAR(expr1) 返回日期expr1部分的年份;
MONTH(expr1) 返回日期expr1部分的月份;
DAY(expr1)返回expr1部分的天數;
WEEKDAY(expr1)返回expr1對應的星期數字
字符串轉換成日期方式,DATE_FORMAT()或STR_TO_DATE(),
兩個函數的格式以下:
DATE_FORMAT(expr1,format)
STR_TO_DATE(expr1, format)
經常使用的日期格式YYYY-MM-DD HH:MM:SS 對應的format爲%Y-%m-%d %H:%i:%S
通用的類型轉換函數:
CAST(expr AS type)
CONVERT(expr,type)
CONVERT(expr USING transcoding_name)
MyISAM |
InnoDB |
|
構 成上的區別: |
每一個MyISAM表在磁盤上存儲三個文件。文件的名字以表的名字開始,擴展名指出文件類型。 .frm文件存儲表定義。 .MYD文件存儲數據 (MYData)。 .MYI文件存儲索引 (MYIndex)。 |
InnoDB表空間數據文件和日誌文件,InnoDB表的大小隻受限於操做系統文件的大小 |
事務處理上方面: |
MyISAM類型的表強調的是性能,其執行速度比InnoDB類型更快,可是不提供事務支持 |
InnoDB提供事務支持事務,外部鍵等高級 數據庫功能 |
SELECT UPDATE,INSERT,Delete操 做 |
若是執行大量的SELECT,MyISAM是更好的選擇 |
1.若是你的數據執行大量的INSERT或UPDATE,出於性能方面的考慮,應該使用InnoDB表 2.DELETE FROM table時,InnoDB不會從新創建表,而是一行一行的 刪除。 3.LOAD TABLE FROM MASTER操做對InnoDB是不起做用的,解決方法是首先把InnoDB表改爲MyISAM表,導入數據後再改爲InnoDB表,可是對於使用的額外的InnoDB特性(例如外鍵)的表不適用 |
表的具體行數 |
select count(*) from table,MyISAM只要簡單的讀出保存好的行數,注意的是,當count(*)語句包含 where條件時,兩種表的操做是同樣的 |
InnoDB中不保存表的具體行數,也就是說,執行select count(*) from table時,InnoDB要掃描一遍整個表來計算有多少行 |
鎖 |
表鎖,MyISAM表鎖讀寫互相阻塞,寫鎖優先級高於讀鎖。參數選項low_priority_updates設置寫鎖優先級比讀鎖低、參數選項concurrent_insert配置是否使用併發插入特性,concurrent_insert=0 表示不容許併發插入,concurrent_insert=1表示容許對沒有空數據塊的表使用併發插入(缺省),concurrent_insert=2表示對全部表容許併發插入 |
提供行鎖(locking on row level),提供與Oracle類型一致的不加鎖讀取(non-locking read in SELECTs)。MySQL的行鎖是針對索引加的鎖,不是針對記錄加的鎖,在不經過索引條件查詢的時候,InnoDB使用的是表鎖,而不是行鎖。 另外,即使在條件中使用了索引字段,可是否使用索引來檢索數據是由MySQL經過判斷不一樣執行計劃的代價來決定的,若是MySQL認爲全表掃描效率更高,好比對一些很小的表,它就不會使用索引,這種狀況下InnoDB將使用表鎖,而不是行鎖 |