亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

淺談數(shù)據(jù)庫設(shè)計(jì)技巧

系統(tǒng) 1737 0

說到數(shù)據(jù)庫,我認(rèn)為不能不先談數(shù)據(jù)結(jié)構(gòu)。1996年,在我初入大學(xué)學(xué)習(xí)計(jì)算機(jī)編程時(shí),當(dāng)時(shí)的老師就告訴我們說:計(jì)算機(jī)程序=數(shù)據(jù)結(jié)構(gòu)+算法。盡管現(xiàn)在的程序開發(fā)已由面向過程為主逐步過渡到面向?qū)ο鬄橹鳎疫€是深深贊同8年前老師的告訴我們的公式:計(jì)算機(jī)程序=數(shù)據(jù)結(jié)構(gòu)+算法。面向?qū)ο蟮某绦蜷_發(fā),要做的第一件事就是,先分析整個(gè)程序中需處理的數(shù)據(jù),從中提取出抽象模板,以這個(gè)抽象模板設(shè)計(jì)類,再在其中逐步添加處理其數(shù)據(jù)的函數(shù)(即算法),最后,再給類中的數(shù)據(jù)成員和函數(shù)劃分訪問權(quán)限,從而實(shí)現(xiàn)封裝。

  數(shù)據(jù)庫的最初雛形據(jù)說源自美國一個(gè)奶牛場的記賬薄(紙質(zhì)的,由此可見,數(shù)據(jù)庫并不一定是存儲(chǔ)在電腦里的數(shù)據(jù)^_^),里面記錄的是該奶牛場的收支賬目,程序員在將其整理、錄入到電腦中時(shí)從中受到啟發(fā)。當(dāng)按照規(guī)定好的數(shù)據(jù)結(jié)構(gòu)所采集到的數(shù)據(jù)量大到一定程度后,出于程序執(zhí)行效率的考慮,程序員將其中的檢索、更新維護(hù)等功能分離出來,做成單獨(dú)調(diào)用的模塊,這個(gè)模塊后來就慢慢發(fā)展、演變成現(xiàn)在我們所接觸到的數(shù)據(jù)庫管理系統(tǒng)(DBMS)——程序開發(fā)中的一個(gè)重要分支。

  下面進(jìn)入正題,首先按我個(gè)人所接觸過的程序給數(shù)據(jù)庫設(shè)計(jì)人員的功底分一下類:
  1、沒有系統(tǒng)學(xué)習(xí)過數(shù)據(jù)結(jié)構(gòu)的程序員。這類程序員的作品往往只是他們的即興玩具,他們往往習(xí)慣只設(shè)計(jì)有限的幾個(gè)表,實(shí)現(xiàn)某類功能的數(shù)據(jù)全部塞在一個(gè)表中,各表之間幾乎毫無關(guān)聯(lián)。網(wǎng)上不少的免費(fèi)管理軟件都是這樣的東西,當(dāng)程序功能有限,數(shù)據(jù)量不多的時(shí)候,其程序運(yùn)行起來沒有什么問題,但是如果用其管理比較重要的數(shù)據(jù),風(fēng)險(xiǎn)性非常大。
  2、系統(tǒng)學(xué)習(xí)過數(shù)據(jù)結(jié)構(gòu),但是還沒有開發(fā)過對(duì)程序效率要求比較高的管理軟件的程序員。這類人多半剛從學(xué)校畢業(yè)不久,他們?cè)谠O(shè)計(jì)數(shù)據(jù)庫表結(jié)構(gòu)時(shí),嚴(yán)格按照教科書上的規(guī)定,死扣E-R圖和3NF(別灰心,所有的數(shù)據(jù)庫設(shè)計(jì)高手都是從這一步開始的)。他們的作品,對(duì)于一般的access型輕量級(jí)的管理軟件,已經(jīng)夠用。但是一旦該系統(tǒng)需要添加新功能,原有的數(shù)據(jù)庫表差不多得進(jìn)行大換血。
  3、第二類程序員,在經(jīng)歷過數(shù)次程序效率的提升,以及功能升級(jí)的折騰后,終于升級(jí)成為數(shù)據(jù)庫設(shè)計(jì)的老鳥,第一類程序員眼中的高人。這類程序員可以勝任二十個(gè)表以上的中型商業(yè)數(shù)據(jù)管理系統(tǒng)的開發(fā)工作。他們知道該在什么樣的情況下保留一定的冗余數(shù)據(jù)來提高程序效率,而且其設(shè)計(jì)的數(shù)據(jù)庫可拓展性較好,當(dāng)用戶需要添加新功能時(shí),原有數(shù)據(jù)庫表只需做少量修改即可。
  4、在經(jīng)歷過上十個(gè)類似數(shù)據(jù)庫管理軟件的重復(fù)設(shè)計(jì)后,第三類程序員中堅(jiān)持下來沒有轉(zhuǎn)行,而是希望從中找出“偷懶”竅門的有心人會(huì)慢慢覺悟,從而完成量變到質(zhì)變的轉(zhuǎn)換。他們所設(shè)計(jì)的數(shù)據(jù)庫表結(jié)構(gòu)有一定的遠(yuǎn)見,能夠預(yù)測到未來功能升級(jí)所需要的數(shù)據(jù),從而預(yù)先留下伏筆。這類程序員目前大多晉級(jí)成數(shù)據(jù)挖掘方面的高級(jí)軟件開發(fā)人員。
  5、第三類程序員或第四類程序員,在對(duì)現(xiàn)有的各家數(shù)據(jù)庫管理系統(tǒng)的原理和開發(fā)都有一定的鉆研后,要么在其基礎(chǔ)上進(jìn)行二次開發(fā),要么自行開發(fā)一套有自主版權(quán)的通用數(shù)據(jù)庫管理系統(tǒng)。

  我個(gè)人正處于第三類的末期,所以下面所列出的一些設(shè)計(jì)技巧只適合第二類和部分第三類數(shù)據(jù)庫設(shè)計(jì)人員。同時(shí),由于我很少碰到有興趣在這方面深鉆下去的同行,所以文中難免出現(xiàn)錯(cuò)誤和遺漏,在此先行聲明,歡迎大家指正,不要藏私哦8)

  一、樹型關(guān)系的數(shù)據(jù)表
  不少程序員在進(jìn)行數(shù)據(jù)庫設(shè)計(jì)的時(shí)候都遇到過樹型關(guān)系的數(shù)據(jù),例如常見的類別表,即一個(gè)大類,下面有若干個(gè)子類,某些子類又有子類這樣的情況。當(dāng)類別不確定,用戶希望可以在任意類別下添加新的子類,或者刪除某個(gè)類別和其下的所有子類,而且預(yù)計(jì)以后其數(shù)量會(huì)逐步增長,此時(shí)我們就會(huì)考慮用一個(gè)數(shù)據(jù)表來保存這些數(shù)據(jù)。按照教科書上的教導(dǎo),第二類程序員大概會(huì)設(shè)計(jì)出類似這樣的數(shù)據(jù)表結(jié)構(gòu):

類別表_1(Type_table_1)
名稱     類型    約束條件   說明
type_id??  ? int???  ?? 無重復(fù)  ?? 類別標(biāo)識(shí),主鍵
type_name   char(50)??? 不允許為空?? 類型名稱,不允許重復(fù)
type_father?? int???????? 不允許為空?? 該類別的父類別標(biāo)識(shí),如果是頂節(jié)點(diǎn)的話設(shè)定為某個(gè)唯一值

  這樣的設(shè)計(jì)短小精悍,完全滿足3NF,而且可以滿足用戶的所有要求。是不是這樣就行呢?答案是NO!Why?

  我們來估計(jì)一下用戶希望如何羅列出這個(gè)表的數(shù)據(jù)的。對(duì)用戶而言,他當(dāng)然期望按他所設(shè)定的層次關(guān)系一次羅列出所有的類別,例如這樣:
總類別
  類別1
    類別1.1
      類別1.1.1
    類別1.2
  類別2
    類別2.1
  類別3
    類別3.1
    類別3.2
  ……

  看看為了實(shí)現(xiàn)這樣的列表顯示(樹的先序遍歷),要對(duì)上面的表進(jìn)行多少次檢索?注意,盡管類別1.1.1可能是在類別3.2之后添加的記錄,答案仍然是N次。這樣的效率對(duì)于少量的數(shù)據(jù)沒什么影響,但是日后類型擴(kuò)充到數(shù)十條甚至上百條記錄后,單單列一次類型就要檢索數(shù)十次該表,整個(gè)程序的運(yùn)行效率就不敢恭維了。或許第二類程序員會(huì)說,那我再建一個(gè)臨時(shí)數(shù)組或臨時(shí)表,專門保存類型表的先序遍歷結(jié)果,這樣只在第一次運(yùn)行時(shí)檢索數(shù)十次,再次羅列所有的類型關(guān)系時(shí)就直接讀那個(gè)臨時(shí)數(shù)組或臨時(shí)表就行了。其實(shí),用不著再去分配一塊新的內(nèi)存來保存這些數(shù)據(jù),只要對(duì)數(shù)據(jù)表進(jìn)行一定的擴(kuò)充,再對(duì)添加類型的數(shù)量進(jìn)行一下約束就行了,要完成上面的列表只需一次檢索就行了。下面是擴(kuò)充后的數(shù)據(jù)表結(jié)構(gòu):

類別表_2(Type_table_2)
名稱     類型    約束條件   ??????????????????? 說明
type_id??  ? int????  ? 無重復(fù)  ?????????????????? 類別標(biāo)識(shí),主鍵
type_name   char(50)??? 不允許為空?????????????????? 類型名稱,不允許重復(fù)
type_father?? int???????? 不允許為空?????????????????? 該類別的父類別標(biāo)識(shí),如果是頂節(jié)點(diǎn)的話設(shè)定為某個(gè)唯一值
type_layer??? char(6)???? 限定3層,初始值為000000?????? 類別的先序遍歷,主要為減少檢索數(shù)據(jù)庫的次數(shù)

  按照這樣的表結(jié)構(gòu),我們來看看上面例子記錄在表中的數(shù)據(jù)是怎樣的:

type_id????? type_name????????? type_father????????? type_layer
1???????????? 總類別?????????????? 0???????????????? 000000
2???????????? 類別1??????????????? 1???????????????? 010000
3???????????? 類別1.1????????????? 2???????????????? 010100
4???????????? 類別1.2????????????? 2???????????????? 010200
5???????????? 類別2??????????????? 1???????????????? 020000
6???????????? 類別2.1????????????? 5???????????????? 020100
7???????????? 類別3??????????????? 1???????????????? 030000
8???????????? 類別3.1????????????? 7???????????????? 030100
9???????????? 類別3.2????????????? 7???????????????? 030200
10??????????? 類別1.1.1??????????? 3???????????????? 010101
……

  現(xiàn)在按type_layer的大小來檢索一下:SELECT * FROM Type_table_2 ORDER BY type_layer

列出記錄集如下:

type_id????? type_name????????? type_father????????? type_layer
1???????????? 總類別?????????????? 0???????????????? 000000
2???????????? 類別1??????????????? 1???????????????? 010000
3???????????? 類別1.1????????????? 2???????????????? 010100
10??????????? 類別1.1.1??????????? 3???????????????? 010101
4???????????? 類別1.2????????????? 2???????????????? 010200
5???????????? 類別2??????????????? 1???????????????? 020000
6???????????? 類別2.1????????????? 5???????????????? 020100
7???????????? 類別3??????????????? 1???????????????? 030000
8???????????? 類別3.1????????????? 7???????????????? 030100
9???????????? 類別3.2????????????? 7???????????????? 030200
……

  現(xiàn)在列出的記錄順序正好是先序遍歷的結(jié)果。在控制顯示類別的層次時(shí),只要對(duì)type_layer字段中的數(shù)值進(jìn)行判斷,每2位一組,如大于0則向右移2個(gè)空格。當(dāng)然,我這個(gè)例子中設(shè)定的限制條件是最多3層,每層最多可設(shè)99個(gè)子類別,只要按用戶的需求情況修改一下type_layer的長度和位數(shù),即可更改限制層數(shù)和子類別數(shù)。其實(shí),上面的設(shè)計(jì)不單單只在類別表中用到,網(wǎng)上某些可按樹型列表顯示的論壇程序大多采用類似的設(shè)計(jì)。

  或許有人認(rèn)為,Type_table_2中的type_father字段是冗余數(shù)據(jù),可以除去。如果這樣,在插入、刪除某個(gè)類別的時(shí)候,就得對(duì)type_layer 的內(nèi)容進(jìn)行比較繁瑣的判定,所以我并沒有消去type_father字段,這也正符合數(shù)據(jù)庫設(shè)計(jì)中適當(dāng)保留冗余數(shù)據(jù)的來降低程序復(fù)雜度的原則,后面我會(huì)舉一個(gè)故意增加數(shù)據(jù)冗余的案例。

  二、商品信息表的設(shè)計(jì)
  假設(shè)你是一家百貨公司電腦部的開發(fā)人員,某天老板要求你為公司開發(fā)一套網(wǎng)上電子商務(wù)平臺(tái),該百貨公司有數(shù)千種商品出售,不過目前僅打算先在網(wǎng)上銷售數(shù)十種方便運(yùn)輸?shù)纳唐罚?dāng)然,以后可能會(huì)陸續(xù)在該電子商務(wù)平臺(tái)上增加新的商品出售。現(xiàn)在開始進(jìn)行該平臺(tái)數(shù)據(jù)庫的商品信息表的設(shè)計(jì)。每種出售的商品都會(huì)有相同的屬性,如商品編號(hào),商品名稱,商品所屬類別,相關(guān)信息,供貨廠商,內(nèi)含件數(shù),庫存,進(jìn)貨價(jià),銷售價(jià),優(yōu)惠價(jià)。你很快就設(shè)計(jì)出4個(gè)表:商品類型表(Wares_type),供貨廠商表(Wares_provider),商品信息表(Wares_info):

商品類型表(Wares_type)
名稱     類型    約束條件   ??????????????????? 說明
type_id??  ? int???  ?? 無重復(fù)  ?????????????????? 類別標(biāo)識(shí),主鍵
type_name   char(50)??? 不允許為空?????????????????? 類型名稱,不允許重復(fù)
type_father?? int???????? 不允許為空?????????????????? 該類別的父類別標(biāo)識(shí),如果是頂節(jié)點(diǎn)的話設(shè)定為某個(gè)唯一值
type_layer??? char(6)???? 限定3層,初始值為000000?????? 類別的先序遍歷,主要為減少檢索數(shù)據(jù)庫的次數(shù)

供貨廠商表(Wares_provider)
名稱     類型    約束條件   ??????????????????? 說明
provider_id?? int???  ?? 無重復(fù)  ?????????????????? 供貨商標(biāo)識(shí),主鍵
provider_name char(100)?? 不允許為空?????????????????? 供貨商名稱

商品信息表(Wares_info)
名稱    ? 類型    約束條件   ??????????????????? 說明
wares_id?????? int???  ? 無重復(fù)  ???????????????????? 商品標(biāo)識(shí),主鍵
wares_name???? char(100)? 不允許為空???????????????????? 商品名稱
wares_type   int??????? 不允許為空           商品類型標(biāo)識(shí),和Wares_type.type_id關(guān)聯(lián)
wares_info???? char(200)? 允許為空?????????????????????? 相關(guān)信息
provider?????? int??????? 不允許為空???????????????????? 供貨廠商標(biāo)識(shí),和Wares_provider.provider_id關(guān)聯(lián)
setnum???????? int??????? 初始值為1????????????????????? 內(nèi)含件數(shù),默認(rèn)為1
stock????????? int??????? 初始值為0????????????????????? 庫存,默認(rèn)為0
buy_price????? money????? 不允許為空???????????????????? 進(jìn)貨價(jià)
sell_price???? money????? 不允許為空???????????????????? 銷售價(jià)
discount?????? money????? 不允許為空???????????????????? 優(yōu)惠價(jià)

  你拿著這3個(gè)表給老板檢查,老板希望能夠再添加一個(gè)商品圖片的字段,不過只有一部分商品有圖片。OK,你在商品信息表(Wares_info)中增加了一個(gè)haspic的BOOL型字段,然后再建了一個(gè)新表——商品圖片表(Wares_pic):

商品圖片表(Wares_pic)
名稱    ? 類型    約束條件   ??????????????????? 說明
pic_id??????? int???  ?? 無重復(fù)  ???????????????????? 商品圖片標(biāo)識(shí),主鍵
wares_id????? int???????? 不允許為空???????????????????? 所屬商品標(biāo)識(shí),和Wares_info.wares_id關(guān)聯(lián)
pic_address  char(200)?? 不允許為空           圖片存放路徑

  程序開發(fā)完成后,完全滿足老板目前的要求,于是正式啟用。一段時(shí)間后,老板打算在這套平臺(tái)上推出新的商品銷售,其中,某類商品全部都需添加“長度”的屬性。第一輪折騰來了……當(dāng)然,你按照添加商品圖片表的老方法,在商品信息表(Wares_info)中增加了一個(gè)haslength的BOOL型字段,又建了一個(gè)新表——商品長度表(Wares_length):

商品長度表(Wares_length)
名稱    ? 類型    約束條件   ??????????????????? 說明
length_id???? int???  ?? 無重復(fù)  ???????????????????? 商品圖片標(biāo)識(shí),主鍵
wares_id????? int???????? 不允許為空???????????????????? 所屬商品標(biāo)識(shí),和Wares_info.wares_id關(guān)聯(lián)
length ????? char(20)??? 不允許為空           商品長度說明

  剛剛改完沒多久,老板又打算上一批新的商品,這次某類商品全部需要添加“寬度”的屬性。你咬了咬牙,又照方抓藥,添加了商品寬度表(Wares_width)。又過了一段時(shí)間,老板新上的商品中有一些需要添加“高度”的屬性,你是不是開始覺得你所設(shè)計(jì)的數(shù)據(jù)庫按照這種方式增長下去,很快就能變成一個(gè)迷宮呢?那么,有沒有什么辦法遏制這種不可預(yù)見性,但卻類似重復(fù)的數(shù)據(jù)庫膨脹呢?我在閱讀《敏捷軟件開發(fā):原則、模式與實(shí)踐》中發(fā)現(xiàn)作者舉過類似的例子:7.3 “Copy”程序。其中,我非常贊同敏捷軟件開發(fā)這個(gè)觀點(diǎn):在最初幾乎不進(jìn)行預(yù)先設(shè)計(jì),但是一旦需求發(fā)生變化,此時(shí)作為一名追求卓越的程序員,應(yīng)該從頭審查整個(gè)架構(gòu)設(shè)計(jì),在此次修改中設(shè)計(jì)出能夠滿足日后類似修改的系統(tǒng)架構(gòu)。下面是我在需要添加“長度”的屬性時(shí)所提供的修改方案:

  去掉商品信息表(Wares_info)中的haspic字段,添加商品額外屬性表(Wares_ex_property)和商品額外信息表(Wares_ex_info)2個(gè)表來完成添加新屬性的功能。

商品額外屬性表(Wares_ex_property)
名稱    ? 類型    約束條件   ??????????????????? 說明
ex_pid??????? int???  ?? 無重復(fù)  ???????????????????? 商品額外屬性標(biāo)識(shí),主鍵
p_name??????? char(20)??? 不允許為空???????????????????? 額外屬性名稱

商品額外信息表(Wares_ex_info)
名稱    ??? 類型    約束條件   ??????????????????? 說明
ex_iid????????? int???  ?? 無重復(fù)  ???????????????????? 商品額外信息標(biāo)識(shí),主鍵
wares_id??????? int???????? 不允許為空???????????????????? 所屬商品標(biāo)識(shí),和Wares_info.wares_id關(guān)聯(lián)
property_id ?? int???????? 不允許為空           商品額外屬性標(biāo)識(shí),和Wares_ex_property.ex_pid關(guān)聯(lián)
property_value? char(200)?? 不允許為空???????????????????? 商品額外屬性值

  在商品額外屬性表(Wares_ex_property)中添加2條記錄:
ex_pid??????????? p_name
1??????????????? 商品圖片
2??????????????? 商品長度

  再在整個(gè)電子商務(wù)平臺(tái)的后臺(tái)管理功能中追加一項(xiàng)商品額外屬性管理的功能,以后添加新的商品時(shí)出現(xiàn)新的屬性,只需利用該功能往商品額外屬性表(Wares_ex_property)中添加一條記錄即可。不要害怕變化,被第一顆子彈擊中并不是壞事,壞的是被相同軌道飛來的第二顆、第三顆子彈擊中。第一顆子彈來得越早,所受的傷越重,之后的抵抗力也越強(qiáng)8)(待續(xù))

  三、多用戶及其權(quán)限管理的設(shè)計(jì)
  開發(fā)數(shù)據(jù)庫管理類的軟件,不可能不考慮多用戶和用戶權(quán)限設(shè)置的問題。盡管目前市面上的大、中型的后臺(tái)數(shù)據(jù)庫系統(tǒng)軟件都提供了多用戶,以及細(xì)至某個(gè)數(shù)據(jù)庫內(nèi)某張表的權(quán)限設(shè)置的功能,我個(gè)人建議:一套成熟的數(shù)據(jù)庫管理軟件,還是應(yīng)該自行設(shè)計(jì)用戶管理這塊功能,原因有二:
  1.那些大、中型后臺(tái)數(shù)據(jù)庫系統(tǒng)軟件所提供的多用戶及其權(quán)限設(shè)置都是針對(duì)數(shù)據(jù)庫的共有屬性,并不一定能完全滿足某些特例的需求;
  2.不要過多的依賴后臺(tái)數(shù)據(jù)庫系統(tǒng)軟件的某些特殊功能,多種大、中型后臺(tái)數(shù)據(jù)庫系統(tǒng)軟件之間并不完全兼容。否則一旦日后需要轉(zhuǎn)換數(shù)據(jù)庫平臺(tái)或后臺(tái)數(shù)據(jù)庫系統(tǒng)軟件版本升級(jí),之前的架構(gòu)設(shè)計(jì)很可能無法重用。

  下面看看如何自行設(shè)計(jì)一套比較靈活的多用戶管理模塊,即該數(shù)據(jù)庫管理軟件的系統(tǒng)管理員可以自行添加新用戶,修改已有用戶的權(quán)限,刪除已有用戶。首先,分析用戶需求,列出該數(shù)據(jù)庫管理軟件所有需要實(shí)現(xiàn)的功能;然后,根據(jù)一定的聯(lián)系對(duì)這些功能進(jìn)行分類,即把某類用戶需使用的功能歸為一類;最后開始建表:

功能表(Function_table)
名稱     類型    約束條件   說明
f_id????????? int???  ?? 無重復(fù)  ?? 功能標(biāo)識(shí),主鍵
f_name??????? char(20)??? 不允許為空?? 功能名稱,不允許重復(fù)
f_desc??????? char(50)??? 允許為空???? 功能描述

用戶組表(User_group)
名稱     類型    約束條件   說明
group_id????? int???????? 無重復(fù)??????? 用戶組標(biāo)識(shí),主鍵
group_name??? char(20)??? 不允許為空??? 用戶組名稱
group_power?? char(100)?? 不允許為空??? 用戶組權(quán)限表,內(nèi)容為功能表f_id的集合

用戶表(User_table)
名稱     類型    約束條件   說明
user_id?????? int???????? 無重復(fù)??????? 用戶標(biāo)識(shí),主鍵
user_name???? char(20)??? 無重復(fù)??????? 用戶名
user_pwd????? char(20)??? 不允許為空??? 用戶密碼
user_type???? int???????? 不允許為空??? 所屬用戶組標(biāo)識(shí),和User_group.group_id關(guān)聯(lián)

  采用這種用戶組的架構(gòu)設(shè)計(jì),當(dāng)需要添加新用戶時(shí),只需指定新用戶所屬的用戶組;當(dāng)以后系統(tǒng)需要添加新功能或?qū)εf有功能權(quán)限進(jìn)行修改時(shí),只用操作功能表和用戶組表的記錄,原有用戶的功能即可相應(yīng)隨之變化。當(dāng)然,這種架構(gòu)設(shè)計(jì)把數(shù)據(jù)庫管理軟件的功能判定移到了前臺(tái),使得前臺(tái)開發(fā)相對(duì)復(fù)雜一些。但是,當(dāng)用戶數(shù)較大(10人以上),或日后軟件升級(jí)的概率較大時(shí),這個(gè)代價(jià)是值得的。


  四、簡潔的批量m:n設(shè)計(jì)
  碰到m:n的關(guān)系,一般都是建立3個(gè)表,m一個(gè),n一個(gè),m:n一個(gè)。但是,m:n有時(shí)會(huì)遇到批量處理的情況,例如到圖書館借書,一般都是允許用戶同時(shí)借閱n本書,如果要求按批查詢借閱記錄,即列出某個(gè)用戶某次借閱的所有書籍,該如何設(shè)計(jì)呢?讓我們建好必須的3個(gè)表先:

書籍表(Book_table)
名稱     類型    約束條件   說明
book_id?????? int???????? 無重復(fù)??????? 書籍標(biāo)識(shí),主鍵
book_no?????? char(20)??? 無重復(fù)??????? 書籍編號(hào)
book_name???? char(100)?? 不允許為空??? 書籍名稱
……

借閱用戶表(Renter_table)
名稱     類型    約束條件   說明
renter_id???? int???????? 無重復(fù)??????? 用戶標(biāo)識(shí),主鍵
renter_name?? char(20)??? 不允許為空??? 用戶姓名
……

借閱記錄表(Rent_log)
名稱     類型    約束條件   說明
rent_id?????? int???????? 無重復(fù)??????? 借閱記錄標(biāo)識(shí),主鍵
r_id????????? int???????? 不允許為空??? 用戶標(biāo)識(shí),和Renter_table.renter_id關(guān)聯(lián)
b_id????????? int???????? 不允許為空??? 書籍標(biāo)識(shí),和Book_table.book_id關(guān)聯(lián)
rent_date???? datetime??? 不允許為空??? 借閱時(shí)間
……

  為了實(shí)現(xiàn)按批查詢借閱記錄,我們可以再建一個(gè)表來保存批量借閱的信息,例如:

批量借閱表(Batch_rent)
名稱     類型    約束條件   說明
batch_id????? int???????? 無重復(fù)??????? 批量借閱標(biāo)識(shí),主鍵
batch_no????? int???????? 不允許為空??? 批量借閱編號(hào),同一批借閱的batch_no相同
rent_id?????? int???????? 不允許為空??? 借閱記錄標(biāo)識(shí),和Rent_log.rent_id關(guān)聯(lián)
batch_date??? datetime??? 不允許為空??? 批量借閱時(shí)間

  這樣的設(shè)計(jì)好嗎?我們來看看為了列出某個(gè)用戶某次借閱的所有書籍,需要如何查詢?首先檢索批量借閱表(Batch_rent),把符合條件的的所有記錄的rent_id字段的數(shù)據(jù)保存起來,再用這些數(shù)據(jù)作為查詢條件帶入到借閱記錄表(Rent_log)中去查詢。那么,有沒有什么辦法改進(jìn)呢?下面給出一種簡潔的批量設(shè)計(jì)方案,不需添加新表,只需修改一下借閱記錄表(Rent_log)即可。修改后的記錄表(Rent_log)如下:

借閱記錄表(Rent_log)
名稱     類型    約束條件   說明
rent_id?????? int???????? 無重復(fù)??????? 借閱記錄標(biāo)識(shí),主鍵
r_id????????? int???????? 不允許為空??? 用戶標(biāo)識(shí),和Renter_table.renter_id關(guān)聯(lián)
b_id????????? int???????? 不允許為空??? 書籍標(biāo)識(shí),和Book_table.book_id關(guān)聯(lián)
batch_no????? int???????? 不允許為空??? 批量借閱編號(hào),同一批借閱的batch_no相同
rent_date???? datetime??? 不允許為空??? 借閱時(shí)間
……

  其中,同一次借閱的batch_no和該批第一條入庫的rent_id相同。舉例:假設(shè)當(dāng)前最大rent_id是64,接著某用戶一次借閱了3本書,則批量插入的3條借閱記錄的batch_no都是65。之后另外一個(gè)用戶租了一套碟,再插入出租記錄的rent_id是68。采用這種設(shè)計(jì),查詢批量借閱的信息時(shí),只需使用一條標(biāo)準(zhǔn)T_SQL的嵌套查詢即可。當(dāng)然,這種設(shè)計(jì)不符合3NF,但是和上面標(biāo)準(zhǔn)的3NF設(shè)計(jì)比起來,哪一種更好呢?答案就不用我說了吧。


  五、冗余數(shù)據(jù)的取舍
  上篇的“樹型關(guān)系的數(shù)據(jù)表”中保留了一個(gè)冗余字段,這里的例子更進(jìn)一步——添加了一個(gè)冗余表。先看看例子:我原先所在的公司為了解決員工的工作餐,和附近的一家小餐館聯(lián)系,每天吃飯記賬,費(fèi)用按人數(shù)平攤,月底由公司現(xiàn)金結(jié)算,每個(gè)人每個(gè)月的工作餐費(fèi)從工資中扣除。當(dāng)然,每天吃飯的人員和人數(shù)都不是固定的,而且,由于每頓工作餐的所點(diǎn)的菜色不同,每頓的花費(fèi)也不相同。例如,星期一中餐5人花費(fèi)40元,晚餐2人花費(fèi)20,星期二中餐6人花費(fèi)36元,晚餐3人花費(fèi)18元。為了方便計(jì)算每個(gè)人每個(gè)月的工作餐費(fèi),我寫了一個(gè)簡陋的就餐記賬管理程序,數(shù)據(jù)庫里有3個(gè)表:

員工表(Clerk_table)
名稱     類型    約束條件   說明
clerk_id????? int???????? 無重復(fù)??????? 員工標(biāo)識(shí),主鍵
clerk_name??? char(10)??? 不允許為空??? 員工姓名

每餐總表(Eatdata1)
名稱     類型    約束條件   說明
totle_id????? int???????? 無重復(fù)??????? 每餐總表標(biāo)識(shí),主鍵
persons?????? char(100)?? 不允許為空??? 就餐員工的員工標(biāo)識(shí)集合
eat_date????? datetime??? 不允許為空??? 就餐日期
eat_type????? char(1)???? 不允許為空??? 就餐類型,用來區(qū)分中、晚餐
totle_price?? money?????? 不允許為空??? 每餐總花費(fèi)
persons_num?? int???????? 不允許為空??? 就餐人數(shù)

就餐計(jì)費(fèi)細(xì)表(Eatdata2)
名稱     類型    約束條件   說明
id??????????? int???????? 無重復(fù)??????? 就餐計(jì)費(fèi)細(xì)表標(biāo)識(shí),主鍵
t_id????????? int???????? 不允許為空??? 每餐總表標(biāo)識(shí),和Eatdata1.totle_id關(guān)聯(lián)
c_id????????? int???????? 不允許為空??? 員工標(biāo)識(shí)標(biāo)識(shí),和Clerk_table.clerk_id關(guān)聯(lián)
price???????? money?????? 不允許為空??? 每人每餐花費(fèi)

  其中,就餐計(jì)費(fèi)細(xì)表(Eatdata2)的記錄就是把每餐總表(Eatdata1)的一條記錄按就餐員工平攤拆開,是個(gè)不折不扣的冗余表。當(dāng)然,也可以把每餐總表(Eatdata1)的部分字段合并到就餐計(jì)費(fèi)細(xì)表(Eatdata2)中,這樣每餐總表(Eatdata1)就成了冗余表,不過這樣所設(shè)計(jì)出來的就餐計(jì)費(fèi)細(xì)表重復(fù)數(shù)據(jù)更多,相比來說還是上面的方案好些。但是,就是就餐計(jì)費(fèi)細(xì)表(Eatdata2)這個(gè)冗余表,在做每月每人餐費(fèi)統(tǒng)計(jì)的時(shí)候,大大簡化了編程的復(fù)雜度,只用類似這么一條查詢語句即可統(tǒng)計(jì)出每人每月的寄餐次數(shù)和餐費(fèi)總帳:

SELECT clerk_name AS personname,COUNT(c_id) as eattimes,SUM(price) AS ptprice FROM Eatdata2 JOIN Clerk_tabsle ON (c_id=clerk_id) JOIN eatdata1 ON (totleid=tid) WHERE eat_date>=CONVERT(datetime,'"&the_date&"') AND eat_date<DATEADD(month,1,CONVERT(datetime,'"&the_date&"')) GROUP BY c_id

  想象一下,如果不用這個(gè)冗余表,每次統(tǒng)計(jì)每人每月的餐費(fèi)總帳時(shí)會(huì)多麻煩,程序效率也夠嗆。那么,到底什么時(shí)候可以增加一定的冗余數(shù)據(jù)呢?我認(rèn)為有2個(gè)原則:

  1、用戶的整體需求。當(dāng)用戶更多的關(guān)注于,對(duì)數(shù)據(jù)庫的規(guī)范記錄按一定的算法進(jìn)行處理后,再列出的數(shù)據(jù)。如果該算法可以直接利用后臺(tái)數(shù)據(jù)庫系統(tǒng)的內(nèi)嵌函數(shù)來完成,此時(shí)可以適當(dāng)?shù)脑黾尤哂嘧侄危踔寥哂啾韥肀4孢@些經(jīng)過算法處理后的數(shù)據(jù)。要知道,對(duì)于大批量數(shù)據(jù)的查詢,修改或刪除,后臺(tái)數(shù)據(jù)庫系統(tǒng)的效率遠(yuǎn)遠(yuǎn)高于我們自己編寫的代碼。
  2、簡化開發(fā)的復(fù)雜度。現(xiàn)代軟件開發(fā),實(shí)現(xiàn)同樣的功能,方法有很多。盡管不必要求程序員精通絕大部分的開發(fā)工具和平臺(tái),但是還是需要了解哪種方法搭配哪種開發(fā)工具的程序更簡潔,效率更高一些。冗余數(shù)據(jù)的本質(zhì)就是用空間換時(shí)間,尤其是目前硬件的發(fā)展遠(yuǎn)遠(yuǎn)高于軟件,所以適當(dāng)?shù)娜哂嗍强梢越邮艿摹2贿^我還是在最后再強(qiáng)調(diào)一下:不要過多的依賴平臺(tái)和開發(fā)工具的特性來簡化開發(fā),這個(gè)度要是沒把握好的話,后期維護(hù)升級(jí)會(huì)栽大跟頭的。

?

本文來自CSDN博客: http://blog.csdn.net/hedylin/archive/2007/04/03/1550088.aspx

淺談數(shù)據(jù)庫設(shè)計(jì)技巧


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長非常感激您!手機(jī)微信長按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對(duì)您有幫助就好】

您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會(huì)非常 感謝您的哦!!!

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 日本欧美中文字幕 | 久久夜色视频 | 香蕉综合网 | 中文字幕亚洲综合精品一区 | 中国美女牲交一级毛片 | 国产福利一区二区三区在线视频 | 日本精品一区二区三区在线观看 | 亚洲网址在线观看 | 狠狠色噜噜狠狠狠米奇9999 | 最近中文字幕无吗高清视频 | 一级毛片成人免费看免费不卡 | 日韩欧美影视 | 久久激情影院 | 国产精品嘿咻嘿咻在线播放 | 久久综合九色综合国产 | 成人久久18免费网 | 免费毛片网 | 久热久 | 能在线观看的一区二区三区 | 免费国产成人午夜私人影视 | 青草娱乐极品免费视频 | 欧美日韩亚洲一区二区 | 亚洲国产二区三区久久 | 一级成人a免费视频 | 青青青爽在线视频观看大全 | 成人私人影院在线版 | 色偷偷亚洲第一成人综合网址 | 老司机午夜影院 | 第一国内永久免费福利视频 | 国产欧美一区二区三区免费看 | 91国在线 | 午夜欧美在线 | 欧美成人性做爰 | 五月天在线免费视频 | 日韩中文字幕在线视频 | 日韩精品免费一区二区 | 久久免费视频在线观看 | 奇米影视777888| 伊人丁香狠狠色综合久久 | 国产网红福利 | 免费网站日本永久免费观看 |