21. 避免使用觸發(fā)器
觸發(fā)器的功能通??梢杂闷渌绞綄?shí)現。在調試程序時(shí)觸發(fā)器可能成為干擾。假如你確實(shí)需要采用觸發(fā)器,你最好集中對它文檔化。
22. 包含版本機制
建議你在數據庫中引入版本控制機制來(lái)確定使用中的數據庫的版本。無(wú)論如何你都要實(shí)現這一要求。時(shí)間一長(cháng),用戶(hù)的需求總是會(huì )改變的。最終可能會(huì )要求修改數據庫結構。雖然你可以通過(guò)檢查新字段或者索引來(lái)確定數據庫結構的版本,但我發(fā)現把版本信息直接存放到數據庫中不更為方便嗎?。
23. 給文本字段留足余量
ID 類(lèi)型的文本字段,比如客戶(hù)ID 或定單號等等都應該設置得比一般想象更大,因為時(shí)間不長(cháng)你多半就會(huì )因為要添加額外的字符而難堪不已。比方說(shuō),假設你的客戶(hù)ID 為10 位數長(cháng)。那你應該把數據庫表字段的長(cháng)度設為12 或者13 個(gè)字符長(cháng)。這算浪費空間嗎?是有一點(diǎn),但也沒(méi)你想象的那么多:一個(gè)字段加長(cháng)3 個(gè)字符在有1 百萬(wàn)條記錄,再加上一點(diǎn)索引的情況下才不過(guò)讓整個(gè)數據庫多占據3MB 的空間。但這額外占據的空間卻無(wú)需將來(lái)重構整個(gè)數據庫就可以實(shí)現數據庫規模的增長(cháng)了。
24. 列命名技巧
我們發(fā)現,假如你給每個(gè)表的列名都采用統一的前綴,那么在編寫(xiě)SQL 表達式的時(shí)候會(huì )得到大大的簡(jiǎn)化。這樣做也確實(shí)有缺點(diǎn),比如破壞了自動(dòng)表連接工具的作用,后者把公共列名同某些數據庫聯(lián)系起來(lái),不過(guò)就連這些工具有時(shí)不也連接錯誤嘛。舉個(gè)簡(jiǎn)單的例子,假設有兩個(gè)表:
Customer 和Order。Customer 表的前綴是cu_,所以該表內的子段名如下:cu_name_id、cu_surname、cu_initials 和cu_address 等。Order 表的前綴是or_,所以子段名是:or_order_id、or_cust_name_id、or_quantity 和or_description 等。
這樣從數據庫中選出全部數據的SQL 語(yǔ)句可以寫(xiě)成如下所示:
Select * from Customer, Order
Where cu_surname = "MYNAME"
and cu_name_id = or_cust_name_id
and or_quantity = 1;
在沒(méi)有這些前綴的情況下則寫(xiě)成這個(gè)樣子:
Select * from Customer, Order
Where Customer.surname = "MYNAME"
and Customer.name_id = Order.cust_name_id
and Order.quantity = 1
第1 個(gè)SQL 語(yǔ)句沒(méi)少鍵入多少字符。但如果查詢(xún)涉及到5 個(gè)表乃至更多的列你就知道這個(gè)技巧多有用了。
第3 部分— 選擇鍵和索引
1. 數據采掘要預先計劃
我所在的市場(chǎng)部門(mén)一度要處理8 萬(wàn)多份聯(lián)系方式,同時(shí)填寫(xiě)每個(gè)客戶(hù)的必要數據(這絕對不是小活)。我從中還要確定出一組客戶(hù)作為市場(chǎng)目標。當我從最開(kāi)始設計表和字段的時(shí)候,我試圖不在主索引里增加太多的字段以便加快數據庫的運行速度。然后我意識到特定的組查詢(xún)和信息采掘既不準確速度也不快。結果只好在主索引中重建而且合并了數據字段。我發(fā)現有一個(gè)指示計劃相當關(guān)鍵——當我想創(chuàng )建系統類(lèi)型查找時(shí)為什么要采用號碼作為主索引字段呢?我可以用傳真號碼進(jìn)行檢索,但是它幾乎就象系統類(lèi)型一樣對我來(lái)說(shuō)并不重要。采用后者作為主字段,數據庫更新后重新索引和檢索就快多了。
可操作數據倉庫(ODS)和數據倉庫(DW)這兩種環(huán)境下的數據索引是有差別的。在DW 環(huán)境下,你要考慮銷(xiāo)售部門(mén)是如何組織銷(xiāo)售活動(dòng)的。他們并不是數據庫管理員,但是他們確定表內的鍵信息。這里設計人員或者數據庫工作人員應該分析數據庫結構從而確定出性能和正確輸出之間的最佳條件。
2. 使用系統生成的主鍵
這一天類(lèi)同技巧1,但我覺(jué)得有必要在這里重復提醒大家。假如你總是在設計數據庫的時(shí)候采用系統生成的鍵作為主鍵,那么你實(shí)際控制了數據庫的索引完整性。這樣,數據庫和非人工機制就有效地控制了對存儲數據中每一行的訪(fǎng)問(wèn)。
采用系統生成鍵作為主鍵還有一個(gè)優(yōu)點(diǎn):當你擁有一致的鍵結構時(shí),找到邏輯缺陷很容易。
3. 分解字段用于索引
為了分離命名字段和包含字段以支持用戶(hù)定義的報表,請考慮分解其他字段(甚至主鍵)為其組成要素以便用戶(hù)可以對其進(jìn)行索引。索引將加快SQL 和報表生成器腳本的執行速度。比方說(shuō),我通常在必須使用SQL LIKE 表達式的情況下創(chuàng )建報表,因為case number 字段無(wú)法分解為year、serial number、case type 和defendant code 等要素。性能也會(huì )變壞。假如年度和類(lèi)型字段可以分解為索引字段那么這些報表運行起來(lái)就會(huì )快多了。
4. 鍵設計4 原則
· 為關(guān)聯(lián)字段創(chuàng )建外鍵。
· 所有的鍵都必須唯一。
· 避免使用復合鍵。
· 外鍵總是關(guān)聯(lián)唯一的鍵字段。
5. 別忘了索引
索引是從數據庫中獲取數據的最高效方式之一。95%的數據庫性能問(wèn)題都可以采用索引技術(shù)得到解決。作為一條規則,我通常對邏輯主鍵使用唯一的成組索引,對系統鍵(作為存儲過(guò)程)采用唯一的非成組索引,對任何外鍵列采用非成組索引。不過(guò),索引就象是鹽,太多了菜就篌了。你得考慮數據庫的空間有多大,表如何進(jìn)行訪(fǎng)問(wèn),還有這些訪(fǎng)問(wèn)是否主要用作讀寫(xiě)。
大多數數據庫都索引自動(dòng)創(chuàng )建的主鍵字段,但是可別忘了索引外鍵,它們也是經(jīng)常使用的鍵,比如運行查詢(xún)顯示主表和所有關(guān)聯(lián)表的某條記錄就用得上。還有,不要索引memo/note 字段,不要索引大型字段(有很多字符),這樣作會(huì )讓索引占用太多的存儲空間。
6. 不要索引常用的小型表
不要為小型數據表設置任何鍵,假如它們經(jīng)常有插入和刪除操作就更別這樣作了。對這些插入和刪除操作的索引維護可能比掃描表空間消耗更多的時(shí)間。
7. 不要把社會(huì )保障號碼(SSN)選作鍵
永遠都不要使用SSN 作為數據庫的鍵。除了隱私原因以外,須知政府越來(lái)越趨向于不準許把SSN 用作除收入相關(guān)以外的其他目的,SSN 需要手工輸入。永遠不要使用手工輸入的鍵作為主鍵,因為一旦你輸入錯誤,你唯一能做的就是刪除整個(gè)記錄然后從頭開(kāi)始。
上個(gè)世紀70 年代我還在讀大學(xué)的時(shí)候,我記得那時(shí)SSN 還曾被用做學(xué)號,當然盡管這么做是非法的。而且人們也都知道這是非法的,但他們已經(jīng)習慣了。后來(lái),隨著(zhù)盜取身份犯罪案件的增加,我現在的大學(xué)校園正痛苦地從一大攤子數據中把SSN 刪除。
8. 不要用用戶(hù)的鍵
在確定采用什么字段作為表的鍵的時(shí)候,可一定要小心用戶(hù)將要編輯的字段。通常的情況下不要選擇用戶(hù)可編輯的字段作為鍵。這樣做會(huì )迫使你采取以下兩個(gè)措施:
· 在創(chuàng )建記錄之后對用戶(hù)編輯字段的行為施加限制。假如你這么做了,你可能會(huì )發(fā)現你的應用程序在商務(wù)需求突然發(fā)生變化,而用戶(hù)需要編輯那些不可編輯的字段時(shí)缺乏足夠的靈活性。當用戶(hù)在輸入數據之后直到保存記錄才發(fā)現系統出了問(wèn)題他們該怎么想?刪除重建?假如記錄不可重建是否讓用戶(hù)走開(kāi)?
· 提出一些檢測和糾正鍵沖突的方法。通常,費點(diǎn)精力也就搞定了,但是從性能上來(lái)看這樣做的代價(jià)就比較大了。還有,鍵的糾正可能會(huì )迫使你突破你的數據和商業(yè)/用戶(hù)界面層之間的隔離。
所以還是重提一句老話(huà):你的設計要適應用戶(hù)而不是讓用戶(hù)來(lái)適應你的設計。
不讓主鍵具有可更新性的原因是在關(guān)系模式下,主鍵實(shí)現了不同表之間的關(guān)聯(lián)。比如,Customer 表有一個(gè)主鍵CustomerID,而客戶(hù)的定單則存放在另一個(gè)表里。Order 表的主鍵可能是OrderNo 或者OrderNo、CustomerID 和日期的組合。不管你選擇哪種鍵設置,你都需要在Order 表中存放CustomerID 來(lái)保證你可以給下定單的用戶(hù)找到其定單記錄。
假如你在Customer 表里修改了CustomerID,那么你必須找出Order 表中的所有相關(guān)記錄對其進(jìn)行修改。否則,有些定單就會(huì )不屬于任何客戶(hù)——數據庫的完整性就算完蛋了。
如果索引完整性規則施加到表一級,那么在不編寫(xiě)大量代碼和附加刪除記錄的情況下幾乎不可能改變某一條記錄的鍵和數據庫內所有關(guān)聯(lián)的記錄。而這一過(guò)程往往錯誤叢生所以應該盡量避免。
9. 可選鍵有時(shí)可做主鍵
記住,查詢(xún)數據的不是機器而是人。
假如你有可選鍵,你可能進(jìn)一步把它用做主鍵。那樣的話(huà),你就擁有了建立強大索引的能力。這樣可以阻止使用數據庫的人不得不連接數據庫從而恰當的過(guò)濾數據。在嚴格控制域表的數據庫上,這種負載是比較醒目的。如果可選鍵真正有用,那就是達到了主鍵的水準。
我的看法是,假如你有可選鍵,比如國家表內的state_code,你不要在現有不能變動(dòng)的唯一鍵上創(chuàng )建后續的鍵。你要做的無(wú)非是創(chuàng )建毫無(wú)價(jià)值的數據。比如以下的例子:
10. 別忘了外鍵
大多數數據庫索引自動(dòng)創(chuàng )建的主鍵字段。但別忘了索引外鍵字段,它們在你想查詢(xún)主表中的記錄及其關(guān)聯(lián)記錄時(shí)每次都會(huì )用到。還有,不要索引memo/notes 字段而且不要索引大型文本字段(許多字符),這樣做會(huì )讓你的索引占據大量的數據庫空間。
第4 部分— 保證數據的完整性
1. 用約束而非商務(wù)規則強制數據完整性
如果你按照商務(wù)規則來(lái)處理需求,那么你應當檢查商務(wù)層次/用戶(hù)界面:如果商務(wù)規則以后發(fā)生變化,那么只需要進(jìn)行更新即可。
假如需求源于維護數據完整性的需要,那么在數據庫層面上需要施加限制條件。
如果你在數據層確實(shí)采用了約束,你要保證有辦法把更新不能通過(guò)約束檢查的原因采用用戶(hù)理解的語(yǔ)言通知用戶(hù)界面。除非你的字段命名很冗長(cháng),否則字段名本身還不夠。
Select count(*)
from address, state_ref
where
address.state_id = state_ref.state_id
and state_ref.state_code = ‘TN‘
我的做法是這樣的:
Select count(*)
from address
where
and state_code = ‘TN‘
如你因為過(guò)度使用表的后續鍵建立這種表的關(guān)聯(lián),操作負載真得需要考慮一下了。
只要有可能,請采用數據庫系統實(shí)現數據的完整性。這不但包括通過(guò)標準化實(shí)現的完整性而且還包括數據的功能性。在寫(xiě)數據的時(shí)候還可以增加觸發(fā)器來(lái)保證數據的正確性。不要依賴(lài)于商務(wù)層保證數據完整性;它不能保證表之間(外鍵)的完整性所以不能強加于其他完整性規則之上。
2. 分布式數據系統
對分布式系統而言,在你決定是否在各個(gè)站點(diǎn)復制所有數據還是把數據保存在一個(gè)地方之前應該估計一下未來(lái)5 年或者10 年的數據量。當你把數據傳送到其他站點(diǎn)的時(shí)候,最好在數據庫字段中設置一些標記。在目的站點(diǎn)收到你的數據之后更新你的標記。為了進(jìn)行這種數據傳輸,請寫(xiě)下你自己的批處理或者調度程序以特定時(shí)間間隔運行而不要讓用戶(hù)在每天的工作后傳輸數據。本地拷貝你的維護數據,比如計算常數和利息率等,設置版本號保證數據在每個(gè)站點(diǎn)都完全一致。
3. 強制指示完整性
沒(méi)有好辦法能在有害數據進(jìn)入數據庫之后消除它,所以你應該在它進(jìn)入數據庫之前將其剔除。激活數據庫系統的指示完整性特性。這樣可以保持數據的清潔而能迫使開(kāi)發(fā)人員投入更多的時(shí)間處理錯誤條件。
4. 關(guān)系
如果兩個(gè)實(shí)體之間存在多對一關(guān)系,而且還有可能轉化為多對多關(guān)系,那么你最好一開(kāi)始就設置成多對多關(guān)系。從現有的多對一關(guān)系轉變?yōu)槎鄬Χ嚓P(guān)系比一開(kāi)始就是多對多關(guān)系要難得多。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請
點(diǎn)擊舉報。