一、基本命名原則
1.1 字符范圍
只能使用26個(gè)英文字母、下劃線(xiàn)(_)、數(shù)字(0-9)進(jìn)行命名,且首位字符必須是英文字母。
1.2 字母全部小寫(xiě)
所有數(shù)據(jù)庫(kù)對(duì)象命名字母全部小寫(xiě),統(tǒng)一大小寫(xiě)有助于在多數(shù)據(jù)庫(kù)間轉(zhuǎn)移。
1.3 命名長(zhǎng)度
庫(kù)名、表名、字段名稱(chēng)長(zhǎng)度不要超過(guò)32個(gè)字符。
1.4 分段命名
命名中多個(gè)單詞間采用下劃線(xiàn)分割,以便閱讀同時(shí)方便某些工具對(duì)數(shù)據(jù)庫(kù)對(duì)象的映射。并且禁止出現(xiàn)數(shù)字開(kāi)頭,禁止兩個(gè)下劃線(xiàn)中間只出現(xiàn)數(shù)字。
1.5 不用保留字
數(shù)據(jù)庫(kù)對(duì)象命名不能直接使用數(shù)據(jù)庫(kù)保留關(guān)鍵字,但分段中可以使用。如user不能用于表名、列名等,但是user_name可以用于列名,user_info也可以用于表名。(Mysql8.0的754個(gè)關(guān)鍵字其中262個(gè)保留字,詳見(jiàn):MySQL 8.0 Keywords and Reserved Words)
1.6 同義性
對(duì)于同一含義盡量使用相同的單詞命名,不管使用英文單詞、英文縮寫(xiě)還是拼音首字母,以免引起誤解。如telphone在A表中表示移動(dòng)電話(huà)號(hào)碼,在B表中就不應(yīng)該用于表示固定電話(huà)號(hào)碼。盡量避免同一單詞表示多種含義的情況。
1.7 命名方式一致
在一個(gè)系統(tǒng)、一個(gè)項(xiàng)目中盡量采用一致的命名方式,都采用英文單詞或者拼音首字母。尤其要避免在一個(gè)對(duì)象命名中同時(shí)采用英文單詞和拼音首字母。如確實(shí)需要在一個(gè)項(xiàng)目中采用兩種命名方式,考慮系統(tǒng)功能設(shè)計(jì)相關(guān)表(開(kāi)發(fā))使用英文單詞命名,業(yè)務(wù)相關(guān)的表(實(shí)施)使用拼音首字母。
1.8 類(lèi)型一致
同一個(gè)字段在同一個(gè)庫(kù)的不同表中,字段類(lèi)型,長(zhǎng)度,意義應(yīng)該一致。
1.9 字符集
創(chuàng)建數(shù)據(jù)庫(kù)時(shí)可顯式指定字符集,只能使用utf8(推薦首選)或utf8mb4(特殊情況下,比如要存儲(chǔ)表情符號(hào)、罕見(jiàn)字等可以使用)格式,數(shù)據(jù)庫(kù)默認(rèn)字符集為utf8。
二、基本設(shè)計(jì)規(guī)范
2.1 數(shù)據(jù)庫(kù)基本設(shè)計(jì)規(guī)范
· 庫(kù)名建議格式:業(yè)務(wù)系統(tǒng)名稱(chēng)_子系統(tǒng)(模塊)名。
· 備份數(shù)據(jù)庫(kù)使用正式數(shù)據(jù)庫(kù)名加上備份時(shí)間。
· Mysql使用InnoDB存儲(chǔ)引擎。
· 數(shù)據(jù)庫(kù)的查詢(xún)QPS過(guò)高,就需要考慮拆庫(kù),通過(guò)分庫(kù)來(lái)分擔(dān)單個(gè)數(shù)據(jù)庫(kù)的連接壓力。
2.2 數(shù)據(jù)表基本設(shè)計(jì)規(guī)范
· 表名不推薦使用復(fù)數(shù)名詞,表名應(yīng)該僅僅表示表里面的實(shí)體內(nèi)容,不應(yīng)該表示實(shí)體數(shù)量。
· 表的命名推薦格式:“業(yè)務(wù)名稱(chēng)_表的作用”。
· 視圖以v作為前綴,其他命名規(guī)則和表的命名類(lèi)似,命名應(yīng)盡量體現(xiàn)各視圖的功能。
· 備份數(shù)據(jù)庫(kù)表名使用正式表名加上備份時(shí)間。
· 表必須有主鍵,主鍵名稱(chēng)推薦格式:表名_id(外鍵格式同主鍵名,使用其指向的表名_id命名),推薦使用UNSIGNED自增列作為主鍵。
· 表必須包含創(chuàng)建時(shí)間(create_time)、修改時(shí)間(modify_time)和刪除標(biāo)記(is_del)字段。
· 使用 comment 屬性來(lái)描述此表所代表的真正含義。
· 臨時(shí)表或中間表時(shí),建議以tmp_、bak_、日期等作為表名前綴或后綴區(qū)分。
2.3 字段基本設(shè)計(jì)規(guī)范
· 如果修改字段含義或?qū)ψ侄伪硎镜臓顟B(tài)追加時(shí),需要及時(shí)更新字段注釋。
· 使用 comment 屬性來(lái)描述此 字段所代表的真正含義。
· 表達(dá)是與否概念的字段,數(shù)據(jù)類(lèi)型是 unsigned tinyint ( 1 表示是,0 表示否)。任何字段如果為非負(fù)數(shù),必須是 unsigned。
· 字段的長(zhǎng)度設(shè)得盡可能小。
· 用盡量少的存儲(chǔ)空間來(lái)存儲(chǔ)一個(gè)字段的數(shù)據(jù)。
· int(11) 適用于自增主鍵,時(shí)間戳等其它非小數(shù)類(lèi)型的字段。
· 自增列初始值建議設(shè)置為1。
· tinyint適用于表示狀態(tài)或類(lèi)型的字段。
· datetime適用于時(shí)間戳字段。
· varchar(2的n次方) 適用于字符串字段,如果存儲(chǔ)的字符串長(zhǎng)度幾乎相等,使用 char 定長(zhǎng)字符串類(lèi)型。varchar 是可變長(zhǎng)字符串,不預(yù)先分配存儲(chǔ)空間,長(zhǎng)度不要超過(guò) 5000,如果存儲(chǔ)長(zhǎng)度大于此值,定義字段類(lèi)型為 text,獨(dú)立出來(lái)一張表,用主鍵來(lái)對(duì)應(yīng),避免影響其它字段索引效率。
· decimal(10,6) 適用于小數(shù)類(lèi)型的字段,所有小數(shù)類(lèi)型為 decimal,禁止使用 float 和 double。
· text(2048,4096,……) 適用于大量文本存儲(chǔ)字段(盡可能不使用)。
· mediumblob適用于文件圖片存儲(chǔ)(盡可能不使用)。
2.4 索引設(shè)計(jì)規(guī)范
· 索引名必須全部使用小寫(xiě),組合索引建議包含所有字段名,過(guò)長(zhǎng)的字段名可以采用縮寫(xiě)形式。
· 主鍵索引名為:pk_字段標(biāo)識(shí),普通索引名為:idx_字段標(biāo)識(shí),唯一索引名為:uk_字段標(biāo)識(shí)。
· 單張表中索引數(shù)量不超過(guò)5個(gè),單個(gè)索引中的字段數(shù)不超過(guò)5個(gè)。
· 業(yè)務(wù)上具有唯一特性的字段,即使是多個(gè)字段的組合,也必須建成唯一索引。
· 超過(guò)三個(gè)表禁止 join。需要 join 的字段,數(shù)據(jù)類(lèi)型必須絕對(duì)一致。多表關(guān)聯(lián)查詢(xún)時(shí),保證被關(guān)聯(lián)的字段需要有索引。即使雙表 join 也要注意表索引、SQL 性能。
· 字符類(lèi)型字段(char,varchar,tinytext,text,mediumtext,longtext等)上不允許建立索引。
· 頁(yè)面搜索嚴(yán)禁左模糊或者全模糊,如果需要請(qǐng)走搜索引擎來(lái)解決。索引文件具有 B-Tree 的最左前綴匹配特性,如果左邊的值未確定,那么無(wú)法使用此索引。
· SQL 性能優(yōu)化的目標(biāo):至少要達(dá)到 range 級(jí)別,要求是 ref 級(jí)別,如果可以是 const最好。
說(shuō)明:
const 單表中最多只有一個(gè)匹配行(主鍵或者唯一索引),在優(yōu)化階段即可讀取到數(shù)據(jù)。
ref 指的是使用普通的索引(normal index)。
range 對(duì)索引進(jìn)行范圍檢索。
反例:explain 表的結(jié)果,type=index,索引物理文件全掃描,速度非常慢,這個(gè) index 級(jí)別比較 range 還低,與全表掃描是小巫見(jiàn)大巫。
· 防止因字段類(lèi)型不同造成的隱式轉(zhuǎn)換,導(dǎo)致索引失效。
2.5 SQL語(yǔ)句規(guī)范
· 禁止使用存儲(chǔ)過(guò)程、自定義函數(shù)和觸發(fā)器。
· SQL語(yǔ)句中出現(xiàn)的所有表名、表別名、字段名、序列等數(shù)據(jù)庫(kù)對(duì)象都應(yīng)小寫(xiě)。
· SQL語(yǔ)句中出現(xiàn)的系統(tǒng)保留字、內(nèi)置函數(shù)名、SQL保留字、綁定變量等都應(yīng)大寫(xiě)或小寫(xiě),嚴(yán)禁使用大小寫(xiě)混合的書(shū)寫(xiě)。
· 推薦使用單引號(hào)來(lái)表示字符值、字符串。
· 縮進(jìn)應(yīng)為1個(gè)Tab或者4個(gè)字符,所有的縮進(jìn)均為1個(gè)縮進(jìn)量的整數(shù)倍,按照代碼層次對(duì)齊,同層次的SQL語(yǔ)句縮進(jìn)應(yīng)保持一致(縱向?qū)R)。
· 禁止使用SELECT *操作,所有操作必須明確指定列名。
· 使用INSERT語(yǔ)句時(shí),應(yīng)指定插入的字段名,不應(yīng)不指定字段名直接插入VALUES。
· 對(duì)應(yīng)的括號(hào)要求在同一列的位置上,尤其用在子查詢(xún)嵌套中。
· 代碼中需要添加必要的注釋?zhuān)栽鰪?qiáng)代碼的可讀性。
· SQL語(yǔ)句中出現(xiàn)多個(gè)表時(shí),給每個(gè)表加上表別名。
· SELECT語(yǔ)句查詢(xún)的字段,推薦將逗號(hào)(,)寫(xiě)在字段前面。
· SQL語(yǔ)句盡可能避免多表聯(lián)合復(fù)雜查詢(xún)。
· 應(yīng)將SQL語(yǔ)句中的數(shù)據(jù)庫(kù)函數(shù)、計(jì)算表達(dá)式等放置在等號(hào)右邊。
三、關(guān)系表設(shè)計(jì)范式和設(shè)計(jì)原則
2.1 關(guān)系表設(shè)計(jì)范式
對(duì)于數(shù)據(jù)庫(kù)設(shè)計(jì)大有好處。在數(shù)據(jù)庫(kù)設(shè)計(jì)中,為了更好地應(yīng)用設(shè)計(jì)范式,就必須通俗地理解設(shè)計(jì)范式(通俗地理解是夠用的理解,并不是最科學(xué)最準(zhǔn)確的理解):
· 第一范式:1NF是對(duì)屬性的原子性約束,要求屬性具有原子性,不可再分解;
· 第二范式:2NF是對(duì)記錄的惟一性約束,要求記錄有惟一標(biāo)識(shí),即實(shí)體的惟一性;
· 第三范式:3NF是對(duì)字段冗余性的約束,即任何字段不能由其他字段派生出來(lái),它要求字段沒(méi)有冗余。
· BCNF:全稱(chēng)是Boyce Codd Normal Form,是對(duì)3NF的補(bǔ)充,若關(guān)系模式屬于第一范式,且每個(gè)屬性都不傳遞依賴(lài)于鍵碼,則R屬于BC范式。BC范式既檢查非主屬性,又檢查主屬性。當(dāng)只檢查非主屬性時(shí),就成了第三范式。滿(mǎn)足BC范式的關(guān)系都必然滿(mǎn)足第三范式。還可以這么說(shuō): 若一個(gè)關(guān)系達(dá)到了第三范式,并且它只有一個(gè)候選碼,或者它的每個(gè)候選碼都是單屬性,則該關(guān)系自然達(dá)到 BC 范式。
· 第四范式:要求把同一表內(nèi)的多對(duì)多關(guān)系刪除。
· 第五范式:將表分割成盡可能小的塊,為了排除在表中所有的冗余。
一般情況下,一個(gè)數(shù)據(jù)庫(kù)設(shè)計(jì)符合3NF或BCNF就可以了。并且,某些情況下,過(guò)于范式化甚至?xí)?duì)數(shù)據(jù)庫(kù)的邏輯可讀性和使用效率起到阻礙。數(shù)據(jù)庫(kù)中一定程度的冗余并不一定是壞事情。有時(shí)為了提高運(yùn)行效率,就必須降低范式標(biāo)準(zhǔn),適當(dāng)保留冗余數(shù)據(jù)。
2.2 關(guān)系表設(shè)計(jì)原則
· 充分考慮業(yè)務(wù)邏輯和數(shù)據(jù)分離
數(shù)據(jù)庫(kù)只作為一個(gè)保證ACID特性的關(guān)系數(shù)據(jù)的持久化存儲(chǔ)系統(tǒng),盡量減少使用自定義函數(shù)、存儲(chǔ)過(guò)程和視圖,不用觸發(fā)器。
· 組件庫(kù)間表關(guān)聯(lián)少
應(yīng)該根據(jù)系統(tǒng)架構(gòu)中的組件劃分,針對(duì)每個(gè)組件所處理的業(yè)務(wù)進(jìn)行組件單元的數(shù)據(jù)庫(kù)設(shè)計(jì);不同組件間所對(duì)應(yīng)的數(shù)據(jù)庫(kù)表之間的關(guān)聯(lián)應(yīng)盡可能減少,確保組件對(duì)應(yīng)的表之間的獨(dú)立性,為系統(tǒng)或表結(jié)構(gòu)的重構(gòu)提供可能性。
· 領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)
采用領(lǐng)域模型驅(qū)動(dòng)的方式和自頂向下的思路進(jìn)行數(shù)據(jù)庫(kù)設(shè)計(jì),首先分析系統(tǒng)業(yè)務(wù),根據(jù)職責(zé)定義對(duì)象。對(duì)象要符合封裝的特性,確保與職責(zé)相關(guān)的數(shù)據(jù)項(xiàng)被定義在一個(gè)對(duì)象之內(nèi),不會(huì)出現(xiàn)職責(zé)描述缺失或多余。
· 基本表的范式標(biāo)準(zhǔn)
規(guī)范化是關(guān)系表設(shè)計(jì)中的重要概念,它通過(guò)將數(shù)據(jù)分解為更小的關(guān)系表,以消除數(shù)據(jù)的幾余和不一致性。在進(jìn)行規(guī)范化時(shí)應(yīng)遵循以下原則:
第一范式:確保每個(gè)字段的原了性,即每個(gè)字段只包含一個(gè)值。
第二范式:確保每個(gè)非主鍵字段完全依賴(lài)于主鍵,消除部分依賴(lài)。
第三范式:確保每個(gè)非主鍵字段不依賴(lài)于其他非主鍵字段,消除傳遞依賴(lài)。
基本表及其字段之間的關(guān)系,應(yīng)盡量滿(mǎn)足第三范式。但是,滿(mǎn)足第三范式的數(shù)據(jù)庫(kù)設(shè)計(jì),往往不是最好的設(shè)計(jì)。為了提高數(shù)據(jù)庫(kù)的運(yùn)行效率,常常需要降低范式標(biāo)準(zhǔn):適當(dāng)增加冗余,達(dá)到以空間換時(shí)間的目的。
· 實(shí)體和屬性的分離原則
關(guān)系表應(yīng)該將實(shí)體和屬性分離開(kāi)來(lái),每個(gè)實(shí)體應(yīng)該對(duì)應(yīng)一個(gè)關(guān)系表,每個(gè)屬性對(duì)應(yīng)表中的一個(gè)字段。這樣可以保證數(shù)據(jù)的完整性和一致性。
· 主鍵的選擇原則
每個(gè)關(guān)系表應(yīng)該有一個(gè)主鍵,用于唯一標(biāo)識(shí)表中的每一行數(shù)據(jù)。主鍵的選擇應(yīng)遵循以下原則:
主鍵應(yīng)該是穩(wěn)定的,不會(huì)隨著時(shí)間的推移而改變
主鍵應(yīng)該是簡(jiǎn)潔的,并且易于理解和識(shí)別。
主鍵應(yīng)該是唯一的,不會(huì)與其他表中的主鍵沖突。
· 性能優(yōu)化原則
關(guān)系表設(shè)計(jì)不僅要考慮數(shù)據(jù)的完整性和一致性,還要考慮查詢(xún)的性能。在設(shè)計(jì)關(guān)系表時(shí)應(yīng)遵循以下原則:
(1) 盡量避免使用過(guò)多的關(guān)聯(lián)查詢(xún),可以通過(guò)冗余數(shù)據(jù)來(lái)提高查詢(xún)性能。
(2) 合理選擇索引,以加快查詢(xún)速度。索引應(yīng)該選擇那些經(jīng)常被查詢(xún)或用于連接的字段。
(3) 避免使用過(guò)多的字段,只選擇必要的字段。
· 可擴(kuò)展性原則
關(guān)系表設(shè)計(jì)應(yīng)該考慮到系統(tǒng)的可擴(kuò)展性,以便在將來(lái)的需求變化中能夠方便地進(jìn)行擴(kuò)展。在設(shè)計(jì)關(guān)系表時(shí)應(yīng)遵循以下原則:
- 盡量避免使用硬編碼的字段,使用動(dòng)態(tài)字段或擴(kuò)展表來(lái)適應(yīng)未來(lái)的需求變化。
(2) 盡量避免使用過(guò)多的嵌套關(guān)系,以便于后續(xù)的擴(kuò)展和修改。
· 識(shí)別與正確處理多對(duì)多的關(guān)系
若兩個(gè)實(shí)體之間存在多對(duì)多的關(guān)系,則應(yīng)消除這種關(guān)系。消除的辦法是,在兩者之間增加中間表。中間表是業(yè)務(wù)邏輯中的概念,就是將計(jì)算結(jié)果先保存在一個(gè)臨時(shí)的表中,然后再?gòu)倪@個(gè)表中計(jì)算,減少程序的復(fù)雜度。中間表包含兩個(gè)實(shí)體類(lèi)的主鍵作為外鍵,建立兩張表關(guān)聯(lián)關(guān)系。中間表的主鍵通常是采用兩個(gè)實(shí)體表的外鍵作為聯(lián)合主鍵,如果聯(lián)合主鍵無(wú)法唯一確定記錄,可以增加其他字段。
· E—R圖設(shè)計(jì)原則
信息系統(tǒng)的E—R圖沒(méi)有標(biāo)準(zhǔn)原則,因?yàn)樗脑O(shè)計(jì)與畫(huà)法不是惟一的,只要它覆蓋了系統(tǒng)需求的業(yè)務(wù)范圍和功能內(nèi)容,就是可行的。反之要修改E—R圖。盡管它沒(méi)有惟一的標(biāo)準(zhǔn)答案,并不意味著可以隨意設(shè)計(jì)。好的E—R圖的標(biāo)準(zhǔn)是:結(jié)構(gòu)清晰、關(guān)聯(lián)簡(jiǎn)潔、實(shí)體個(gè)數(shù)適中、屬性分配合理、沒(méi)有低級(jí)冗余。
· 防止數(shù)據(jù)庫(kù)設(shè)計(jì)打補(bǔ)丁的方法是“三少一多原則”
(1)一個(gè)數(shù)據(jù)庫(kù)中表的個(gè)數(shù)越少越好。只有表的個(gè)數(shù)少了,才能說(shuō)明系統(tǒng)的E—R圖少而精,去掉了重復(fù)的多余的實(shí)體,形成了對(duì)客觀(guān)世界的高度抽象,進(jìn)行了系統(tǒng)的數(shù)據(jù)集成,防止了打補(bǔ)丁式的設(shè)計(jì);
(2)一個(gè)表中組合主鍵的字段個(gè)數(shù)越少越好。因?yàn)橹麈I的作用,一是建主鍵索引,二是做為子表的外鍵,所以組合主鍵的字段個(gè)數(shù)少了,不僅節(jié)省了運(yùn)行時(shí)間,而且節(jié)省了索引存儲(chǔ)空間;
(3)一個(gè)表中的字段個(gè)數(shù)越少越好。字段個(gè)數(shù)越多,數(shù)據(jù)冗余的可能性越大。設(shè)置字段個(gè)數(shù)少的前提是各個(gè)字段相互獨(dú)立,而不是某個(gè)字段的取值可以由其他字段計(jì)算出來(lái)。當(dāng)然字段個(gè)數(shù)少是相對(duì)的,我們通常會(huì)在數(shù)據(jù)冗余和檢索效率中進(jìn)行平衡。
(4)使用主鍵和外鍵越多越好。數(shù)據(jù)庫(kù)的設(shè)計(jì)實(shí)際上就是定義各種表,以及各種字段之間的關(guān)系。這些關(guān)系越多,證明這些實(shí)體之間的冗余度越低,利用度越高。這樣做的好處在于不僅保證了數(shù)據(jù)表之間的獨(dú)立性,還能提升相互之間的關(guān)聯(lián)使用率。
四、SQL性能優(yōu)化
4.1 SQL優(yōu)化調(diào)整的方向
· 去掉不必要的大型表的全表掃描;
· 緩存小型表的全表掃描;
· 檢驗(yàn)優(yōu)化索引的使用;
· 檢驗(yàn)優(yōu)化的連接技術(shù);
· 盡可能減少執(zhí)行計(jì)劃的Cost。
4.2 優(yōu)化的查詢(xún)語(yǔ)句
絕大多數(shù)情況下,使用索引可以提高查詢(xún)的速度,但如果SQL語(yǔ)句使用不恰當(dāng)?shù)脑?huà),索引將無(wú)法發(fā)揮它應(yīng)有的作用。下面是應(yīng)該注意的幾個(gè)方面:
· 最好是在相同類(lèi)型的字段間進(jìn)行比較的操作。
· 在建有索引的字段上盡量不要使用函數(shù)進(jìn)行操作。
· 在搜索字符型字段時(shí),盡量少用或者避免使用like模糊查詢(xún),會(huì)降低查詢(xún)效率,可以用其它條件查詢(xún)語(yǔ)句代替。
· 應(yīng)該注意避免在查詢(xún)中讓MySQL進(jìn)行自動(dòng)類(lèi)型轉(zhuǎn)換,因?yàn)檗D(zhuǎn)換過(guò)程也會(huì)使索引變得不起作用。
4.3 創(chuàng)建索引來(lái)優(yōu)化性能
索引是提高數(shù)據(jù)庫(kù)性能的常用方法,它可以令數(shù)據(jù)庫(kù)服務(wù)器以比沒(méi)有索引快得多的速度檢索特定的行,尤其是在查詢(xún)語(yǔ)句當(dāng)中包含有MAX(), MIN()和ORDER BY這些命令的時(shí)候,性能提高更為明顯。
一般說(shuō)來(lái),索引應(yīng)建立在那些將用于JOIN, WHERE判斷和ORDER BY排序的字段上。盡量不要對(duì)數(shù)據(jù)庫(kù)中某個(gè)含有大量重復(fù)值的字段建立索引。
4.4 用Where子句替換HAVING子句
使用where子句替換Having子句:避免使用having子句,having只會(huì)在檢索出所有記錄之后才會(huì)對(duì)結(jié)果集進(jìn)行過(guò)濾,這個(gè)處理需要排序分組,如果能通過(guò)where子句提前過(guò)濾查詢(xún)的數(shù)目,就可以減少這方面的開(kāi)銷(xiāo)。
低效率:
|
SELECT JOB, AVG(SAL) FROM EMP GROUP BY JOB HAVING JOB = ‘PRESIDENT’ OR JOB = ‘MANAGER’
|
| |
高效率:
|
SELECT JOB, AVG(SAL) FROM EMP WHERE JOB = ‘PRESIDENT’ OR JOB = ‘MANAGER’ GROUP BY JOB
|
| |
4.5 通過(guò)內(nèi)部函數(shù)提高SQL效率
復(fù)雜的SQL往往犧牲了執(zhí)行效率. 能夠掌握運(yùn)用函數(shù)解決問(wèn)題的方法在實(shí)際工作中是非常有意義的。
4.6 用表的別名(Alias)
當(dāng)在SQL語(yǔ)句中連接多個(gè)表時(shí), 請(qǐng)使用表的別名并把別名前綴用于每個(gè)Column上.這樣一來(lái),就可以減少解析的時(shí)間并減少那些由Column歧義引起的語(yǔ)法錯(cuò)誤。
4.7 用EXISTS替代IN、用NOT EXISTS替代NOT IN
在許多基于基礎(chǔ)表的查詢(xún)中,為了滿(mǎn)足一個(gè)條件,往往需要對(duì)另一個(gè)表進(jìn)行聯(lián)接。在這種情況下,使用EXISTS(或NOT EXISTS)通常將提高查詢(xún)的效率。在子查詢(xún)中,NOT IN子句將執(zhí)行一個(gè)內(nèi)部的排序和合并。無(wú)論在哪種情況下,NOT IN都是最低效的 (因?yàn)樗鼘?duì)子查詢(xún)中的表執(zhí)行了一個(gè)全表遍歷)。為了避免使用NOT IN,我們可以把它改寫(xiě)成外連接(Outer Joins)或NOT EXISTS。
高效率:
|
SELECT 字段1,字段2,字段n FROM emp e WHERE e.emp_no > 0 AND EXISTS (SELECT ‘X’ FROM dept d WHERE e.emp_no = d.emp_no AND loc=’MELB’)
|
| |
低效率:
|
SELECT 字段1, 字段2, 字段n FROM emp e WHERE e.emp_no > 0 AND dept_no IN (SELECT dept_no FROM dept WHERE loc= ‘MELB’)
|
| |
4.8 用EXISTS替換DISTINCT
當(dāng)提交一個(gè)包含一對(duì)多表信息(比如部門(mén)表和雇員表)的查詢(xún)時(shí),避免在SELECT子句中使用DISTINCT。一般可以考慮用EXIST替換,EXISTS使查詢(xún)更為迅速,因?yàn)镽DBMS核心模塊將在子查詢(xún)的條件一旦滿(mǎn)足后,立刻返回結(jié)果。
低效率:
|
SELECT DISTINCT dept_no, dept_name FROM dept d, emp e WHERE d.dept_no = e.dept_no
|
| |
高效率:
|
SELECT dept_no, dept_name FROM dept d WHERE EXISTS ( SELECT ‘X’ FROM emp e WHERE e.dept_no = d.dept_no)
|
| |
4.9 避免在索引列上使用NOT
在索引列上使用NOT會(huì)停止使用索引轉(zhuǎn)而執(zhí)行全表掃描。
4.10 避免在索引列上使用計(jì)算
WHERE子句中,如果索引列是函數(shù)的一部分,優(yōu)化器將不使用索引而使用全表掃描。
低效率:
|
SELECT 字段1, 字段2, 字段n FROM dept WHERE sal * 12 > 25000;
|
| |
高效率:
|
SELECT 字段1,字段2,字段n FROM dept WHERE sal > 25000/12;
|
| |
4.11 用>=替代>
高效率:
|
SELECT 字段1,字段2,字段n FROM emp WHERE dept_no >=4
|
| |
低效率:
|
SELECT 字段1,字段2,字段n FROM emp WHERE dept_no >3
|
| |
兩者的區(qū)別在于, 前者DBMS將直接跳到第一個(gè)DEPT等于4的記錄而后者將首先定位到DEPTNO=3的記錄并且向前掃描到第一個(gè)DEPT大于3的記錄。
4.12 用UNION替換OR (適用于索引列)
通常情況下, 用UNION替換WHERE子句中的OR將會(huì)起到較好的效果。對(duì)索引列使用OR將造成全表掃描。注意,以上規(guī)則只針對(duì)多個(gè)索引列有效。如果有column沒(méi)有被索引,查詢(xún)效率可能會(huì)因?yàn)槟銢](méi)有選擇OR而降低。在下面的例子中,LOC_ID和REGION上都建有索引。
高效:
|
SELECT loc_id, loc_desc, region FROM loc WHERE loc_id = 10 UNION SELECT loc_id, loc_desc, region FROM loc WHERE region= ‘MELBOURNE’
|
| |
低效:
|
SELECT loc_id, loc_desc, region FROM loc WHERE loc_id = 10 OR region= ‘MELBOURNE’
|
| |
如果你堅(jiān)持要用OR,那就需要返回記錄最少的索引列寫(xiě)在最前面。
4.13 避免在索引列上使用IS NULL和IS NOT NULL
避免在索引中使用任何可以為空的列。對(duì)于單列索引,如果列包含空值,索引中將不存在此記錄. 對(duì)于復(fù)合索引,如果每個(gè)列都為空,索引中同樣不存在此記錄. 如果至少有一個(gè)列不為空,則記錄存在于索引中。
低效: (索引失效)
|
SELECT字段1, 字段2, 字段n FROM dept WHERE dept_code IS NOT NULL;
|
| |
高效: (索引有效)
|
SELECT字段1,字段2,字段n FROM dept WHERE dept_code >=0;
|
| |
4.14 使用連接(JOIN)來(lái)代替子查詢(xún)(Sub-Queries)
連接(JOIN).. 之所以更有效率一些,是因?yàn)?MySQL不需要在內(nèi)存中創(chuàng)建臨時(shí)表來(lái)完成這個(gè)邏輯上的需要兩個(gè)步驟的查詢(xún)工作。
這是一段含有子查詢(xún)的語(yǔ)句,為了提高效率可以用join代替
|
SELECT customer_id,customer_name FROM customer_info WHERE customer_id NOT IN (SELECT customer_id FROM sale_info)
|
| |
用join代替后的語(yǔ)句:
|
SELECT customer_id,customer_name FROM customer_info ci LEFT JOIN sale_info si ON ci.customer_id = si.customer_id WHERE si.customer_id IS NULL)
|
| |
4.15 大表進(jìn)行拆分來(lái)提高性能
分析每個(gè)表可能的數(shù)據(jù)增長(zhǎng)量,定義自動(dòng)拆分表規(guī)則。將大表進(jìn)行拆分來(lái)提高性能。
4.16 刪除舊數(shù)據(jù)
預(yù)先考慮數(shù)據(jù)清理規(guī)則:在什么情況下刪除數(shù)據(jù)庫(kù)中的舊數(shù)據(jù),以此來(lái)提高性能。
4.17 制定數(shù)據(jù)庫(kù)備份和災(zāi)難恢復(fù)計(jì)劃
制定定期備份數(shù)據(jù)庫(kù)計(jì)劃。
4.18 盡量把字段設(shè)置為NOT NULL
另外一個(gè)提高效率的方法是在可能的情況下,應(yīng)該盡量把字段設(shè)置為NOT NULL,這樣在將來(lái)執(zhí)行查詢(xún)的時(shí)候,數(shù)據(jù)庫(kù)不用去比較NULL值。
4.19 使用聯(lián)合(UNION)來(lái)代替手動(dòng)創(chuàng)建的臨時(shí)表
用 UNION 來(lái)創(chuàng)建查詢(xún)的時(shí)候,我們只需要用 UNION作為關(guān)鍵字把多個(gè) SELECT 語(yǔ)句連接起來(lái)就可以了,要注意的是所有 SELECT 語(yǔ)句中的字段數(shù)目要想同。下面的例子就演示了一個(gè)使用 UNION的查詢(xún)。
如:
| SELECT name
, phone FROM client UNION SELECT name
, birthdate FROM author UNION SELECT name
, supplier FROM product | | —- |