表的设计与优化
單表設(shè)計(jì)與優(yōu)化
1)設(shè)計(jì)規(guī)范化表,消除數(shù)據(jù)冗余(以使用正確字段類(lèi)型最明顯):
數(shù)據(jù)庫(kù)范式是確保數(shù)據(jù)庫(kù)結(jié)構(gòu)合理,滿足各種查詢需要、避免數(shù)據(jù)庫(kù)操作異常的數(shù)據(jù)庫(kù)設(shè)計(jì)方式。滿足范式要求的表,稱為規(guī)范化表,范式產(chǎn)生于20世紀(jì)70年代初,一般表設(shè)計(jì)滿足前三范式就可以,在這里簡(jiǎn)單介紹一下前三范式。
第一范式(1NF)無(wú)重復(fù)的列
所謂第一范式(1NF)是指在關(guān)系模型中,對(duì)域添加的一個(gè)規(guī)范要求,所有的域都應(yīng)該是原子性的,即數(shù)據(jù)庫(kù)表的每一列都是不可分割的原子數(shù)據(jù)項(xiàng),而不能是集合,數(shù)組,記錄等非原子數(shù)據(jù)項(xiàng)。
第二范式(2NF)屬性
在1NF的基礎(chǔ)上,非碼屬性必須完全依賴于碼[在1NF基礎(chǔ)上消除非主屬性對(duì)主碼的部分函數(shù)依賴]
第三范式(3NF)屬性
在1NF基礎(chǔ)上,任何非主屬性不依賴于其它非主屬性[在2NF基礎(chǔ)上消除傳遞依賴。
通俗點(diǎn)講:
第一范式:屬性(字段)的原子性約束,要求屬性具有原子性,不可再分割;
第二范式:記錄的惟一性約束,要求記錄有惟一標(biāo)識(shí),每條記錄需要有一個(gè)屬性來(lái)做為實(shí)體的唯一標(biāo)識(shí),即每列都要和主鍵相關(guān)。
第三范式:屬性(字段)冗余性的約束,即任何字段不能由其他字段派生出來(lái),在通俗點(diǎn)就是:主鍵沒(méi)有直接關(guān)系的數(shù)據(jù)列必須消除(消除的辦法就是再創(chuàng)建一個(gè)表來(lái)存放他們,當(dāng)然外鍵除外)。即:確保每列都和主鍵列直接相關(guān),而不是間接相關(guān)。
如果數(shù)據(jù)庫(kù)設(shè)計(jì)達(dá)到了完全的標(biāo)準(zhǔn)化,則把所有的表通過(guò)關(guān)鍵字連接在一起時(shí),不會(huì)出現(xiàn)任何數(shù)據(jù)的復(fù)本(repetition)。標(biāo)準(zhǔn)化的優(yōu)點(diǎn)是明顯的,它避免了數(shù)據(jù)冗余,自然就節(jié)省了空間,也對(duì)數(shù)據(jù)的一致性(consistency)提供了根本的保障,杜絕了數(shù)據(jù)不一致的現(xiàn)象,同時(shí)也提高了效率。
(2)適當(dāng)?shù)娜哂?#xff0c;增加計(jì)算列:(實(shí)際開(kāi)發(fā)中必須思考的點(diǎn))
數(shù)據(jù)庫(kù)設(shè)計(jì)的實(shí)用原則是:在數(shù)據(jù)冗余和處理速度之間找到合適的平衡點(diǎn)。
滿足范式的表一定是規(guī)范化的表,但不一定是最佳的設(shè)計(jì)。很多情況下會(huì)為了提高數(shù)據(jù)庫(kù)的運(yùn)行效率,常常需要降低范式標(biāo)準(zhǔn):適當(dāng)增加冗余,達(dá)到以空間換時(shí)間的目的。比如我們有一個(gè)表,產(chǎn)品名稱,單價(jià),庫(kù)存量,總價(jià)值。這個(gè)表是不滿足第三范式的,因?yàn)椤翱們r(jià)值”可以由“單價(jià)”乘以“數(shù)量”得到,說(shuō)明“金額”是冗余字段。但是,增加“總價(jià)值”這個(gè)冗余字段,可以提高查詢統(tǒng)計(jì)的速度,這就是以空間換時(shí)間的作法。合理的冗余可以分散數(shù)據(jù)量大的表的并發(fā)壓力,也可以加快特殊查詢的速度,冗余字段可以有效減少數(shù)據(jù)庫(kù)表的連接,提高效率。
其中”總價(jià)值”就是一個(gè)計(jì)算列,在數(shù)據(jù)庫(kù)中有兩種類(lèi)型:數(shù)據(jù)列和計(jì)算列,數(shù)據(jù)列就是需要我們手動(dòng)或者程序給予賦值的列,計(jì)算列是源于表中其他的數(shù)據(jù)計(jì)算得來(lái),比如這里的”總價(jià)值”
在SQL中創(chuàng)建計(jì)算列:
(3)索引的設(shè)計(jì):
表優(yōu)化的重要途徑,百萬(wàn)級(jí)別的表沒(méi)有索引,注定卡死。
MySQL的分區(qū)
MySQL分區(qū)表是在數(shù)據(jù)庫(kù)層面,MySQL自己實(shí)現(xiàn)的分表功能,在很大程度上簡(jiǎn)化了分表的難度。物理存儲(chǔ)上分區(qū)存儲(chǔ),每個(gè)分區(qū)有獨(dú)立的文件,應(yīng)用程序上還是一張表Range(范圍)–這種模式允許將數(shù)據(jù)劃分不同范圍。例如可以將一個(gè)表通過(guò)年份劃分成若干個(gè)分區(qū)。MySQL5.1開(kāi)始支持表分區(qū)
RANGE分區(qū) -根據(jù)范圍分區(qū),范圍應(yīng)該連續(xù)但是不重疊,使用PARTITION BY RANGE, VALUES LESS THAN關(guān)鍵字。不使用COLUMNS關(guān)鍵字時(shí)RANGE括號(hào)內(nèi)必須為整數(shù)字段名或返回確定整數(shù)的函數(shù)。
List(預(yù)定義列表)–這種模式允許系統(tǒng)通過(guò)預(yù)定義的列表的值來(lái)對(duì)數(shù)據(jù)進(jìn)行分割。
Hash(哈希)–這中模式允許通過(guò)對(duì)表的一個(gè)或多個(gè)列的HashKey進(jìn)行計(jì)算,最后通過(guò)這個(gè)Hash碼不同數(shù)值對(duì)應(yīng)的數(shù)據(jù)區(qū)域進(jìn)行分區(qū)。例如可以建立一個(gè)對(duì)表主鍵進(jìn)行分區(qū)的表。
Key(鍵值)-上面Hash模式的一種延伸,這里的Hash Key是MySQL系統(tǒng)產(chǎn)生的。
分區(qū)的好處是:
可以讓單表存儲(chǔ)更多的數(shù)據(jù)
分區(qū)表的數(shù)據(jù)更容易維護(hù),可以通過(guò)清楚整個(gè)分區(qū)批量刪除大量數(shù)據(jù),也可以增加新的分區(qū)來(lái)支持新插入的數(shù)據(jù)。另外,還可以對(duì)一個(gè)獨(dú)立分區(qū)進(jìn)行優(yōu)化、檢查、修復(fù)等操作
部分查詢能夠從查詢條件確定只落在少數(shù)分區(qū)上,速度會(huì)很快
分區(qū)表的數(shù)據(jù)還可以分布在不同的物理設(shè)備上,從而搞笑利用多個(gè)硬件設(shè)備
可以使用分區(qū)表賴避免某些特殊瓶頸,例如InnoDB單個(gè)索引的互斥訪問(wèn)、ext3文件系統(tǒng)的inode鎖競(jìng)爭(zhēng)
可以備份和恢復(fù)單個(gè)分區(qū)
分區(qū)的限制和缺點(diǎn):
一個(gè)表最多只能有1024個(gè)分區(qū)
如果分區(qū)字段中有主鍵或者唯一索引的列,那么所有主鍵列和唯一索引列都必須包含進(jìn)來(lái)
分區(qū)表無(wú)法使用外鍵約束
NULL值會(huì)使分區(qū)過(guò)濾無(wú)效
所有分區(qū)必須使用相同的存儲(chǔ)引擎
MySQL從5.1開(kāi)始支持分區(qū)功能。分區(qū)一句話就是:把一張表按照某種規(guī)則(range/list/hash/key等)分成多個(gè)區(qū)域(頁(yè)/文件)保存。
MySQL的分表
為什么我們需要分表:
當(dāng)一張的數(shù)據(jù)達(dá)到幾百萬(wàn)時(shí),你查詢一次所花的時(shí)間會(huì)變多,如果有聯(lián)合查詢的話,我想有可能會(huì)死在那兒了。分表的目的就在于此,減小數(shù)據(jù)庫(kù)的負(fù)擔(dān),縮短查詢時(shí)間。
mysql中有一種機(jī)制是表鎖定和行鎖定,為什么要出現(xiàn)這種機(jī)制,是為了保證數(shù)據(jù)的完整性,我舉個(gè)例子來(lái)說(shuō)吧,如果有二個(gè)sql都要修改同一張表的同一條數(shù)據(jù),這個(gè)時(shí)候怎么辦呢,是不是二個(gè)sql都可以同時(shí)修改這條數(shù)據(jù)呢?很顯然mysql對(duì)這種情況的處理是,一種是表鎖定(myisam存儲(chǔ)引擎),一個(gè)是行鎖定(innodb存儲(chǔ)引擎)。表鎖定表示你們都不能對(duì)這張表進(jìn)行操作,必須等我對(duì)表操作完才行。行鎖定也一樣,別的sql必須等我對(duì)這條數(shù)據(jù)操作完了,才能對(duì)這條數(shù)據(jù)進(jìn)行操作。如果數(shù)據(jù)太多,一次執(zhí)行的時(shí)間太長(zhǎng),等待的時(shí)間就越長(zhǎng),這也是我們?yōu)槭裁匆直淼脑颉?/p>
單庫(kù)數(shù)據(jù)庫(kù)-->數(shù)據(jù)庫(kù)讀寫(xiě)分離-->緩存技術(shù)-->搜索技術(shù)-->數(shù)據(jù)的垂直拆分-->數(shù)據(jù)的水平拆分
MySQL的分庫(kù)
大型網(wǎng)站解決存儲(chǔ)瓶頸的問(wèn)題,我們要找準(zhǔn)存儲(chǔ)這個(gè)關(guān)鍵點(diǎn),因?yàn)閿?shù)據(jù)庫(kù)其實(shí)是存儲(chǔ)和運(yùn)算的組合體,但是在我們這個(gè)場(chǎng)景下,存儲(chǔ)是第一位的,當(dāng)存儲(chǔ)是瓶頸時(shí)候我們要狠下心來(lái)盡量多的拋棄數(shù)據(jù)的計(jì)算特點(diǎn),所以上文中我提出我們數(shù)據(jù)庫(kù)就不要濫用計(jì)算功能了例如觸發(fā)器、存儲(chǔ)過(guò)程等等。
數(shù)據(jù)庫(kù)剝離計(jì)算功能不代表不要數(shù)據(jù)的計(jì)算功能,因?yàn)闆](méi)有數(shù)據(jù)的計(jì)算功能數(shù)據(jù)庫(kù)也就沒(méi)價(jià)值了,那么我們要將數(shù)據(jù)庫(kù)的計(jì)算功能進(jìn)行遷移,遷移到程序里面,一般大型系統(tǒng)程序和數(shù)據(jù)庫(kù)都是分開(kāi)部署到不同服務(wù)器上,因此程序里處理數(shù)據(jù)計(jì)算就不會(huì)影響到數(shù)據(jù)庫(kù)所在服務(wù)器的性能,就可以讓安裝數(shù)據(jù)庫(kù)的服務(wù)器專(zhuān)心服務(wù)于存儲(chǔ)。
我們要盡一切可能的把數(shù)據(jù)庫(kù)的變化對(duì)服務(wù)層的影響降到最低,最好是數(shù)據(jù)庫(kù)做拆分后,現(xiàn)有業(yè)務(wù)不要任何的更改,那么我們就得設(shè)計(jì)一個(gè)全新的數(shù)據(jù)訪問(wèn)層,這個(gè)數(shù)據(jù)訪問(wèn)層將數(shù)據(jù)庫(kù)和服務(wù)層進(jìn)行解耦,任何數(shù)據(jù)庫(kù)的變化都由數(shù)據(jù)訪問(wèn)層消化,數(shù)據(jù)訪問(wèn)層對(duì)外接口要高度統(tǒng)一,不要輕易改變。
如果我們?cè)O(shè)計(jì)了數(shù)據(jù)訪問(wèn)層來(lái)解決數(shù)據(jù)庫(kù)拆分的問(wèn)題,數(shù)據(jù)訪問(wèn)層加上數(shù)據(jù)庫(kù)其實(shí)就組合出了一個(gè)分布式數(shù)據(jù)庫(kù)的解決方案,由此可見(jiàn)拆分?jǐn)?shù)據(jù)庫(kù)的難度是很高的,因?yàn)閿?shù)據(jù)庫(kù)將擁有分布式的特性,而分布式開(kāi)發(fā)就意味開(kāi)發(fā)難度的增加。
對(duì)于分布式事務(wù)的處理,我們盡量要從具體問(wèn)題具體分析,不要一感覺(jué)這個(gè)事務(wù)操作本質(zhì)是分布式事務(wù)就去尋找通用的分布式事務(wù)技術(shù)手段,這樣的想法其實(shí)是回避困難的思想,結(jié)果可能會(huì)是把問(wèn)題搞得更加復(fù)雜。
轉(zhuǎn)載于:https://www.cnblogs.com/lcxjingjing/p/9877426.html
總結(jié)
- 上一篇: 同步函数死锁现象
- 下一篇: 对Faster R-CNN的理解(1)