我們一直在路上,隻爲更優質的(de)服務
SMART SERVICE
TIME: 2019-01-25
一、數據庫命令規範
所有數據庫對(duì)象名稱必須使用(yòng)小寫字母并用(yòng)下(xià)劃線分(fēn)割
所有數據庫對(duì)象名稱禁止使用(yòng)mysql保留關鍵字(如果表名中包含關鍵字查詢時(shí),需要将其用(yòng)單引号括起來(lái))
數據庫對(duì)象的(de)命名要能做(zuò)到見名識意,并且最後不要超過32個(gè)字符
臨時(shí)庫表必須以tmp_爲前綴并以日期爲後綴,備份表必須以bak_爲前綴并以日期(時(shí)間戳)爲後綴
所有存儲相同數據的(de)列名和(hé)列類型必須一緻(一般作爲關聯列,如果查詢時(shí)關聯列類型不一緻會自動進行數據類型隐式轉換,會造成列上的(de)索引失效,導緻查詢效率降低)
二、數據庫基本設計規範
1、所有表必須使用(yòng)Innodb存儲引擎
沒有特殊要求(即Innodb無法滿足的(de)功能如:列存儲,存儲空間數據等)的(de)情況下(xià),所有表必須使用(yòng)Innodb存儲引擎(mysql5.5之前默認使用(yòng)Myisam,5.6以後默認的(de)爲Innodb)Innodb 支持事務,支持行級鎖,更好的(de)恢複性,高(gāo)并發下(xià)性能更好
2、數據庫和(hé)表的(de)字符集統一使用(yòng)UTF8
兼容性更好,統一字符集可(kě)以避免由于字符集轉換産生的(de)亂碼,不同的(de)字符集進行比較前需要進行轉換會造成索引失效
3、所有表和(hé)字段都需要添加注釋
使用(yòng)comment從句添加表和(hé)列的(de)備注 從一開始就進行數據字典的(de)維護
4、盡量控制單表數據量的(de)大(dà)小,建議(yì)控制在500萬以内
500萬并不是MySQL數據庫的(de)限制,過大(dà)會造成修改表結構,備份,恢複都會有很大(dà)的(de)問題
可(kě)以用(yòng)曆史數據歸檔(應用(yòng)于日志數據),分(fēn)庫分(fēn)表(應用(yòng)于業務數據)等手段來(lái)控制數據量大(dà)小
5、謹慎使用(yòng)MySQL分(fēn)區(qū)表
分(fēn)區(qū)表在物(wù)理(lǐ)上表現爲多(duō)個(gè)文件,在邏輯上表現爲一個(gè)表 謹慎選擇分(fēn)區(qū)鍵,跨分(fēn)區(qū)查詢效率可(kě)能更低 建議(yì)采用(yòng)物(wù)理(lǐ)分(fēn)表的(de)方式管理(lǐ)大(dà)數據
6、盡量做(zuò)到冷(lěng)熱(rè)數據分(fēn)離,減小表的(de)寬度
MySQL限制每個(gè)表最多(duō)存儲4096列,并且每一行數據的(de)大(dà)小不能超過65535字節 減少磁盤IO,保證熱(rè)數據的(de)内存緩存命中率(表越寬,把表裝載進内存緩沖池時(shí)所占用(yòng)的(de)内存也(yě)就越大(dà),也(yě)會消耗更多(duō)的(de)IO) 更有效的(de)利用(yòng)緩存,避免讀入無用(yòng)的(de)冷(lěng)數據 經常一起使用(yòng)的(de)列放到一個(gè)表中(避免更多(duō)的(de)關聯操作)
7、禁止在表中建立預留字段
預留字段的(de)命名很難做(zuò)到見名識義 預留字段無法确認存儲的(de)數據類型,所以無法選擇合适的(de)類型 對(duì)預留字段類型的(de)修改,會對(duì)表進行鎖定
8、禁止在數據庫中存儲圖片,文件等大(dà)的(de)二進制數據
通(tōng)常文件很大(dà),會短時(shí)間内造成數據量快(kuài)速增長(cháng),數據庫進行數據庫讀取時(shí),通(tōng)常會進行大(dà)量的(de)随機IO操作,文件很大(dà)時(shí),IO操作很耗時(shí) 通(tōng)常存儲于文件服務器,數據庫隻存儲文件地址信息
9、禁止在線上做(zuò)數據庫壓力測試
10、禁止從開發環境,測試環境直接連接生成環境數據庫
三、數據庫字段設計規範
1、優先選擇符合存儲需要的(de)最小的(de)數據類型
列的(de)字段越大(dà),建立索引時(shí)所需要的(de)空間也(yě)就越大(dà),這(zhè)樣一頁中所能存儲的(de)索引節點的(de)數量也(yě)就越少也(yě)越少,在遍曆時(shí)所需要的(de)IO次數也(yě)就越多(duō), 索引的(de)性能也(yě)就越差
1)将字符串轉換成數字類型存儲,如:将IP地址轉換成整形數據。
mysql提供了(le)兩個(gè)方法來(lái)處理(lǐ)ip地址:
插入數據前,先用(yòng)inet_aton把ip地址轉爲整型,可(kě)以節省空間。顯示數據時(shí),使用(yòng)inet_ntoa把整型的(de)ip地址轉爲地址顯示即可(kě)。
2)對(duì)于非負型的(de)數據(如自增ID、整型IP)來(lái)說,要優先使用(yòng)無符号整型來(lái)存儲
因爲:無符号相對(duì)于有符号可(kě)以多(duō)出一倍的(de)存儲空間
VARCHAR(N)中的(de)N代表的(de)是字符數,而不是字節數
使用(yòng)UTF8存儲255個(gè)漢字 Varchar(255)=765個(gè)字節。過大(dà)的(de)長(cháng)度會消耗更多(duō)的(de)内存
2、避免使用(yòng)TEXT、BLOB數據類型,最常見的(de)TEXT類型可(kě)以存儲64k的(de)數據
Mysql内存臨時(shí)表不支持TEXT、BLOB這(zhè)樣的(de)大(dà)數據類型,如果查詢中包含這(zhè)樣的(de)數據,在排序等操作時(shí),就不能使用(yòng)内存臨時(shí)表,必須使用(yòng)磁盤臨時(shí)表進行。
而且對(duì)于這(zhè)種數據,Mysql還(hái)是要進行二次查詢,會使sql性能變得(de)很差,但是不是說一定不能使用(yòng)這(zhè)樣的(de)數據類型。
如果一定要使用(yòng),建議(yì)把BLOB或是TEXT列分(fēn)離到單獨的(de)擴展表中,查詢時(shí)一定不要使用(yòng)select * 而隻需要取出必要的(de)列,不需要TEXT列的(de)數據時(shí)不要對(duì)該列進行查詢。
因爲MySQL對(duì)索引字段長(cháng)度是有限制的(de),所以TEXT類型隻能使用(yòng)前綴索引,并且TEXT列上是不能有默認值的(de)。
3、避免使用(yòng)ENUM類型
4、盡可(kě)能把所有列定義爲NOT NULL
原因:
索引NULL列需要額外的(de)空間來(lái)保存,所以要占用(yòng)更多(duō)的(de)空間;
進行比較和(hé)計算(suàn)時(shí)要對(duì)NULL值做(zuò)特别的(de)處理(lǐ)
5、使用(yòng)TIMESTAMP(4個(gè)字節)或DATETIME類型(8個(gè)字節)存儲時(shí)間
TIMESTAMP 存儲的(de)時(shí)間範圍 1970-01-01 00:00:01 ~ 2038-01-19-03:14:07。
TIMESTAMP 占用(yòng)4字節和(hé)INT相同,但比INT可(kě)讀性高(gāo)
超出TIMESTAMP取值範圍的(de)使用(yòng)DATETIME類型存儲。
經常會有人(rén)用(yòng)字符串存儲日期型的(de)數據(不正确的(de)做(zuò)法):
6、同财務相關的(de)金額類數據必須使用(yòng)decimal類型
Decimal類型爲精準浮點數,在計算(suàn)時(shí)不會丢失精度。占用(yòng)空間由定義的(de)寬度決定,每4個(gè)字節可(kě)以存儲9位數字,并且小數點要占用(yòng)一個(gè)字節。可(kě)用(yòng)于存儲比bigint更大(dà)的(de)整型數據。
四、索引設計規範
1、限制每張表上的(de)索引數量,建議(yì)單張表索引不超過5個(gè)
索引并不是越多(duō)越好!索引可(kě)以提高(gāo)效率同樣可(kě)以降低效率。
索引可(kě)以增加查詢效率,但同樣也(yě)會降低插入和(hé)更新的(de)效率,甚至有些情況下(xià)會降低查詢效率。
因爲mysql優化(huà)器在選擇如何優化(huà)查詢時(shí),會根據統一信息,對(duì)每一個(gè)可(kě)以用(yòng)到的(de)索引來(lái)進行評估,以生成出一個(gè)最好的(de)執行計劃,如果同時(shí)有很多(duō)個(gè)索引都可(kě)以用(yòng)于查詢,就會增加mysql優化(huà)器生成執行計劃的(de)時(shí)間,同樣會降低查詢性能。
2、禁止給表中的(de)每一列都建立單獨的(de)索引
5.6版本之前,一個(gè)sql隻能使用(yòng)到一個(gè)表中的(de)一個(gè)索引,5.6以後,雖然有了(le)合并索引的(de)優化(huà)方式,但是還(hái)是遠(yuǎn)遠(yuǎn)沒有使用(yòng)一個(gè)聯合索引的(de)查詢方式好
3、每個(gè)Innodb表必須有個(gè)主鍵
Innodb是一種索引組織表:數據的(de)存儲的(de)邏輯順序和(hé)索引的(de)順序是相同的(de)。
每個(gè)表都可(kě)以有多(duō)個(gè)索引,但是表的(de)存儲順序隻能有一種 Innodb是按照(zhào)主鍵索引的(de)順序來(lái)組織表的(de)。
不要使用(yòng)更新頻(pín)繁的(de)列作爲主鍵,不适用(yòng)多(duō)列主鍵(相當于聯合索引) 不要使用(yòng)UUID、MD5、HASH、字符串列作爲主鍵(無法保證數據的(de)順序增長(cháng))。
主鍵建議(yì)使用(yòng)自增ID值。
五、常見索引列建議(yì)
并不要将符合1和(hé)2中的(de)字段的(de)列都建立一個(gè)索引,通(tōng)常将1、2中的(de)字段建立聯合索引效果更好
六、如何選擇索引列的(de)順序
建立索引的(de)目的(de)是:希望通(tōng)過索引進行數據查找,減少随機IO,增加查詢性能 ,索引能過濾出越少的(de)數據,則從磁盤中讀入的(de)數據也(yě)就越少。
七、避免建立冗餘索引和(hé)重複索引
因爲這(zhè)樣會增加查詢優化(huà)器生成執行計劃的(de)時(shí)間。
八、優先考慮覆蓋索引
對(duì)于頻(pín)繁的(de)查詢優先考慮使用(yòng)覆蓋索引。
覆蓋索引:就是包含了(le)所有查詢字段(where,select,ordery by,group by包含的(de)字段)的(de)索引
覆蓋索引的(de)好處:
Innodb是以聚集索引的(de)順序來(lái)存儲的(de),對(duì)于Innodb來(lái)說,二級索引在葉子節點中所保存的(de)是行的(de)主鍵信息,
如果是用(yòng)二級索引查詢數據的(de)話(huà),在查找到相應的(de)鍵值後,還(hái)要通(tōng)過主鍵進行二次查詢才能獲取我們真實所需要的(de)數據。而在覆蓋索引中,二級索引的(de)鍵值中可(kě)以獲取所有的(de)數據,避免了(le)對(duì)主鍵的(de)二次查詢 ,減少了(le)IO操作,提升了(le)查詢效率。
由于覆蓋索引是按鍵值的(de)順序存儲的(de),對(duì)于IO密集型的(de)範圍查找來(lái)說,對(duì)比随機從磁盤讀取每一行的(de)數據IO要少的(de)多(duō),因此利用(yòng)覆蓋索引在訪問時(shí)也(yě)可(kě)以把磁盤的(de)随機讀取的(de)IO轉變成索引查找的(de)順序IO。
九、索引SET規範
盡量避免使用(yòng)外鍵約束
十、數據庫SQL開發規範
1、建議(yì)使用(yòng)預編譯語句進行數據庫操作
預編譯語句可(kě)以重複使用(yòng)這(zhè)些計劃,減少SQL編譯所需要的(de)時(shí)間,還(hái)可(kě)以解決動态SQL所帶來(lái)的(de)SQL注入的(de)問題 隻傳參數,比傳遞SQL語句更高(gāo)效 相同語句可(kě)以一次解析,多(duō)次使用(yòng),提高(gāo)處理(lǐ)效率。
2、避免數據類型的(de)隐式轉換
隐式轉換會導緻索引失效。如:select name,phone from customer where id = '111';
3、充分(fēn)利用(yòng)表上已經存在的(de)索引
如a like '%123%',(如果無前置%,隻有後置%,是可(kě)以用(yòng)到列上的(de)索引的(de))
如:有 a,b,c列的(de)聯合索引,在查詢條件中有a列的(de)範圍查詢,則在b,c列上的(de)索引将不會被用(yòng)到,在定義聯合索引時(shí),如果a列要用(yòng)到範圍查找的(de)話(huà),就要把a列放到聯合索引的(de)右側。
因爲not in 也(yě)通(tōng)常會使用(yòng)索引失效。
4、數據庫設計時(shí),應該要對(duì)以後擴展進行考慮
5、程序連接不同的(de)數據庫使用(yòng)不同的(de)賬号,進制跨庫查詢
6、禁止使用(yòng)SELECT * 必須使用(yòng)SELECT <字段列表> 查詢
原因:
7、禁止使用(yòng)不含字段列表的(de)INSERT語句
如:insert into values ('a','b','c');
應使用(yòng)insert into t(c1,c2,c3) values ('a','b','c');
8、避免使用(yòng)子查詢,可(kě)以把子查詢優化(huà)爲join操作
通(tōng)常子查詢在in子句中,且子查詢中爲簡單SQL(不包含union、group by、order by、limit從句)時(shí),才可(kě)以把子查詢轉化(huà)爲關聯查詢進行優化(huà)。
子查詢性能差的(de)原因:
9、避免使用(yòng)JOIN關聯太多(duō)的(de)表
對(duì)于Mysql來(lái)說,是存在關聯緩存的(de),緩存的(de)大(dà)小可(kě)以由join_buffer_size參數進行設置。
在Mysql中,對(duì)于同一個(gè)SQL多(duō)關聯(join)一個(gè)表,就會多(duō)分(fēn)配一個(gè)關聯緩存,如果在一個(gè)SQL中關聯的(de)表越多(duō),所占用(yòng)的(de)内存也(yě)就越大(dà)。
如果程序中大(dà)量的(de)使用(yòng)了(le)多(duō)表關聯的(de)操作,同時(shí)join_buffer_size設置的(de)也(yě)不合理(lǐ)的(de)情況下(xià),就容易造成服務器内存溢出的(de)情況,就會影(yǐng)響到服務器數據庫性能的(de)穩定性。
同時(shí)對(duì)于關聯操作來(lái)說,會産生臨時(shí)表操作,影(yǐng)響查詢效率Mysql最多(duō)允許關聯61個(gè)表,建議(yì)不超過5個(gè)。
10、減少同數據庫的(de)交互次數
數據庫更适合處理(lǐ)批量操作 合并多(duō)個(gè)相同的(de)操作到一起,可(kě)以提高(gāo)處理(lǐ)效率
11、對(duì)應同一列進行or判斷時(shí),使用(yòng)in代替or
in的(de)值不要超過500個(gè)in操作可(kě)以更有效的(de)利用(yòng)索引,or大(dà)多(duō)數情況下(xià)很少能利用(yòng)到索引。
12、禁止使用(yòng)order by rand() 進行随機排序
會把表中所有符合條件的(de)數據裝載到内存中,然後在内存中對(duì)所有數據根據随機生成的(de)值進行排序,并且可(kě)能會對(duì)每一行都生成一個(gè)随機值,如果滿足條件的(de)數據集非常大(dà),就會消耗大(dà)量的(de)CPU和(hé)IO及内存資源。
推薦在程序中獲取一個(gè)随機值,然後從數據庫中獲取數據的(de)方式
13、WHERE從句中禁止對(duì)列進行函數轉換和(hé)計算(suàn)
對(duì)列進行函數轉換或計算(suàn)時(shí)會導緻無法使用(yòng)索引。
不推薦:
推薦:
14、在明(míng)顯不會有重複值時(shí)使用(yòng)UNION ALL而不是UNION
15、拆分(fēn)複雜(zá)的(de)大(dà)SQL爲多(duō)個(gè)小SQL
十一、數據庫操作行爲規範
1、超100萬行的(de)批量寫(UPDATE、DELETE、INSERT)操作,要分(fēn)批多(duō)次進行操作
主從環境中,大(dà)批量操作可(kě)能會造成嚴重的(de)主從延遲,大(dà)批量的(de)寫操作一般都需要執行一定長(cháng)的(de)時(shí)間,而隻有當主庫上執行完成後,才會在其他(tā)從庫上執行,所以會造成主庫與從庫長(cháng)時(shí)間的(de)延遲情況
大(dà)批量寫操作會産生大(dà)量日志,特别是對(duì)于row格式二進制數據而言,由于在row格式中會記錄每一行數據的(de)修改,我們一次修改的(de)數據越多(duō),産生的(de)日志量也(yě)就會越多(duō),日志的(de)傳輸和(hé)恢複所需要的(de)時(shí)間也(yě)就越長(cháng),這(zhè)也(yě)是造成主從延遲的(de)一個(gè)原因。
大(dà)批量修改數據,一定是在一個(gè)事務中進行的(de),這(zhè)就會造成表中大(dà)批量數據進行鎖定,從而導緻大(dà)量的(de)阻塞,阻塞會對(duì)MySQL的(de)性能産生非常大(dà)的(de)影(yǐng)響。
特别是長(cháng)時(shí)間的(de)阻塞會占滿所有數據庫的(de)可(kě)用(yòng)連接,這(zhè)會使生産環境中的(de)其他(tā)應用(yòng)無法連接到數據庫,因此一定要注意大(dà)批量寫操作要進行分(fēn)批。
2、對(duì)于大(dà)表使用(yòng)pt-online-schema-change修改表結構
對(duì)大(dà)表數據結構的(de)修改一定要謹慎,會造成嚴重的(de)鎖表操作,尤其是生産環境,是不能容忍的(de)。
pt-online-schema-change它會首先建立一個(gè)與原表結構相同的(de)新表,并且在新表上進行表結構的(de)修改,然後再把原表中的(de)數據複制到新表中,并在原表中增加一些觸發器。
把原表中新增的(de)數據也(yě)複制到新表中,在行所有數據複制完成之後,把新表命名成原表,并把原來(lái)的(de)表删除掉。
把原來(lái)一個(gè)DDL操作,分(fēn)解成多(duō)個(gè)小的(de)批次進行。
3、禁止爲程序使用(yòng)的(de)賬号賦予super權限
當達到最大(dà)連接數限制時(shí),還(hái)運行1個(gè)有super權限的(de)用(yòng)戶連接super權限隻能留給DBA處理(lǐ)問題的(de)賬号使用(yòng)。
4、對(duì)于程序連接數據庫賬号,遵循權限最小原則
程序使用(yòng)數據庫賬号隻能在一個(gè)DB下(xià)使用(yòng),不準跨庫 程序使用(yòng)的(de)賬号原則上不準有drop權限。