庫表設(shè)計(jì)原則 在互聯(lián)網(wǎng)應(yīng)用中,數(shù)據(jù)庫訪問頻率很高,CPU、內(nèi)存、IO、網(wǎng)絡(luò)都是緊缺資源,因此在滿足業(yè)務(wù)的前提下,降低SQL尤其是高頻SQL的資源消耗就是個(gè)非常重要的優(yōu)化原則了,在設(shè)計(jì)表結(jié)構(gòu)時(shí),應(yīng)該考慮哪些是高頻執(zhí)行的SQL從而采取針對(duì)性措施。
1:?jiǎn)伪碜侄螖?shù)應(yīng)控制在20個(gè)以內(nèi)。一個(gè)表的字段越多,面臨的業(yè)務(wù)場(chǎng)景就會(huì)越復(fù)雜,面臨可能的變化也越多。當(dāng)查詢時(shí),也會(huì)因?yàn)樾枰^濾的字段過多,導(dǎo)致更多的IO消耗。這個(gè)原則也可以用另外用另外一種形式表達(dá):拆分表中字段來分離冷熱數(shù)據(jù)。大字段和訪問頻率低的字段都會(huì)降低查詢的效率,分離冷熱數(shù)據(jù)后,能提示熱數(shù)據(jù)的訪問性能,降低IO消耗,提高緩存命中概率。
2:控制表的數(shù)據(jù)量。當(dāng)數(shù)據(jù)量超過千萬級(jí)別后,即使硬件性能強(qiáng)大,sql執(zhí)行時(shí)間也會(huì)下降。
3:選擇字段類型時(shí),在滿足正確存儲(chǔ)業(yè)務(wù)數(shù)據(jù)要求的前提下,選擇最短的。越小的字段,訪問效率越高。不要使用TEXT、BLOB類型;不得不使用TEXT、BLOB類型時(shí),拆分到單獨(dú)表中;用DECIMAL代替FLOAT和DOUBLE存儲(chǔ)精確浮點(diǎn)數(shù);使用整數(shù)替代浮點(diǎn)數(shù):比如用分為單位表示以元為單位的金額;使用數(shù)字或ENUM代替字符或字符串。
4:如果可能的話所有字段均定義為not null,因?yàn)閚ull值使索引失效。對(duì)于數(shù)據(jù)量比較大的表而言,索引失效時(shí)查詢將是災(zāi)難性的低效。
索引設(shè)計(jì)使用原則: 索引對(duì)于性能來說非常關(guān)鍵,尤其是數(shù)據(jù)量非常越大時(shí)。查詢時(shí)使用到索引可以減少查詢時(shí)掃描的數(shù)據(jù)量、避免排序、將隨機(jī)IO轉(zhuǎn)為順序IO。代價(jià)就是修改或刪除數(shù)據(jù)時(shí),索引需要重新排序,降低了性能。索引還能使查詢條件命中的索引作為行鎖的條件
1:將索引建立在高區(qū)分度字段上。索引是按照字段內(nèi)容排序的,如果字段值區(qū)分度不高,在索引中將有很多大段的相同值,用這樣的索引查詢時(shí),過濾效果非常不明顯,所以不要在區(qū)分度低的字段上創(chuàng)建索引。字段值區(qū)分度高時(shí)可以根據(jù)查詢值迅速定位查詢結(jié)果,提示查詢效率。
2:索引應(yīng)該建立在短字段上。盡量不要建在長字符串上,如果不可避免,可以選擇字符串的開頭幾位。建立索引時(shí)要把字段內(nèi)容保存到索引中,所以字段越長,索引占得硬盤空間也就越大,查詢時(shí)消耗的硬盤IO資源也就越大,耗時(shí)越長。
3:創(chuàng)建復(fù)合索引時(shí)索引的列順序至關(guān)重要。查詢有多個(gè)條件時(shí),適合使用復(fù)合索引查詢。如果有多種查詢組合條件,復(fù)合索引建立得當(dāng)?shù)脑?,?fù)合索引可以復(fù)用。建立復(fù)合索引時(shí),自個(gè)字段的順序仍然優(yōu)先按照區(qū)分度,其次再考慮索引復(fù)用。
4:不要在索引列上進(jìn)行數(shù)學(xué)運(yùn)算、函數(shù)運(yùn)算(會(huì)使索引失效)。
5:?jiǎn)螐埍碇兴饕龜?shù)量不超過5個(gè),單個(gè)索引中的字段數(shù)不超過5個(gè),通常將選擇性最高的列放在最前面。如果一個(gè)表的索引太多,最可能的原因是開始時(shí)這個(gè)表擔(dān)負(fù)了太多的職責(zé),考慮將此表的職責(zé)拆分。
SQL使用原則:
1:拒絕大sql,盡可能不做表之間的join操作。原因: a、MySQL更擅長簡(jiǎn)單查詢,尤其是單表主鍵或二級(jí)索引查詢;mysql一條sql只能使用一個(gè)cpu,有大表join的情況下,性能下降明顯; b、大sql不僅慢,而且會(huì)大幅度降低數(shù)據(jù)庫的并發(fā)能力,甚至拖垮數(shù)據(jù)庫; c、使用多條簡(jiǎn)單sql,使緩存命中率更高,還可以使用多核; d、高并發(fā)場(chǎng)景下,不要使用兩個(gè)或以上的表join。
2:限制返回結(jié)果條數(shù),否則返回滿足條件的所有記錄。大多數(shù)情況下這是不必要的,應(yīng)用在處理返回的大量結(jié)果時(shí)可能崩潰。
3:不要使用select *,只查詢需要的列 a、select * 消耗了更多的cpu,內(nèi)存,io,網(wǎng)絡(luò)資源; b、使用具體字段除了減少資源消耗,還減小了表增加字段時(shí)的影響;
4:避免關(guān)聯(lián)子查詢。mysql的關(guān)聯(lián)子查詢實(shí)現(xiàn)非常糟糕,除非有非常高深的優(yōu)化功力,否則不要寫關(guān)聯(lián)子查詢。
5:避免負(fù)向查詢,不要使用NOT、!=、<>、!<、!>、NOT EXISTS、NOT IN、 NOT LIKE等。不能使用索引,導(dǎo)致全表掃描,效率低下。
6:避免使用count。除非是非常小的表,否則盡可能使用冗余字段計(jì)數(shù)或其他方式。
7:分頁時(shí)避免傳統(tǒng)的limit offset, size方式分頁。這種方式隨著偏移量大,性能越來越差,可以考慮把分頁轉(zhuǎn)換成條件查詢。
8:使用in代替or,in的值不超過200個(gè)。IN的效率(O(log n))比OR的效率(O(n))高很多。
9:使用預(yù)編譯的sql。使用預(yù)編譯的sql不僅能防sql注入攻擊,還可以避免mysql服務(wù)器編譯的開銷。