sqlserver主鍵設(shè)計(jì)的注意點(diǎn)
更新時(shí)間:2012年07月27日 09:27:02 作者:
在數(shù)據(jù)庫設(shè)計(jì)中,主鍵用于惟一地標(biāo)識(shí)表中的某一條記錄
在設(shè)計(jì)主鍵的時(shí)候往往需要考慮以下幾點(diǎn):
1.無意義性:此處無意義是從用戶的角度來定義的。這種無意義在一定程度上也會(huì)減少數(shù)據(jù)庫的信息冗余。常常有人稱呼主鍵為內(nèi)部標(biāo)識(shí),為什么會(huì)這樣稱呼,原因之一在于“內(nèi)部”,所謂內(nèi)部從某種程度上來說就是指表記錄,從大的范圍來說就是數(shù)據(jù)庫,如果你在設(shè)計(jì)的時(shí)候選擇了對(duì)用戶來說有意義的信息來作為主鍵,那么遲早會(huì)面對(duì)用戶提出對(duì)這塊信息進(jìn)行更新的需求,那么你就違背了它應(yīng)有的靜態(tài)。
2.靜態(tài)性:主鍵除了唯一地標(biāo)識(shí)一條記錄及外鍵的關(guān)聯(lián)外,應(yīng)不再考慮其他的意義,最理想的狀態(tài)就是在產(chǎn)生后不再變動(dòng),所以在主鍵值產(chǎn)生后應(yīng)考慮不對(duì)他進(jìn)行更新等操作。如果進(jìn)行了更新操作那么至少說明這塊信息對(duì)于用戶來說是有一定的意義,那么你就違背了應(yīng)有的無意義性。(對(duì)數(shù)據(jù)進(jìn)行整合等操作時(shí)可能需要對(duì)主鍵進(jìn)行處理,這樣做是為了保證數(shù)據(jù)庫的完整性——記錄的唯一,不在此考慮范圍之內(nèi)。)
無意義性往往可以決定其靜態(tài)性。
3.簡(jiǎn)短性:既包含主鍵組成字段數(shù)量要少,還包含主鍵中單個(gè)字段存儲(chǔ)類型簡(jiǎn)短,一般采用整形;對(duì)于前者主要考慮的是外鍵關(guān)聯(lián)的因素;對(duì)于后者主要考慮的是性能。主鍵的簡(jiǎn)短對(duì)表的關(guān)聯(lián)便捷性及檢索的性能有極大的幫助。
看看下面具有缺陷的“主生產(chǎn)計(jì)劃表”主鍵設(shè)計(jì)方案(MsSQL):
--主表
CREATE TABLE PP_MPSHeader(
BillNo VARCHAR(20) NOT NULL PRIMARY KEY,
PlanDate DATETIME NOT NULL
)
--從表
CREATE TABLE PP_MPSBody(
BillNo VARCHAR(20) NOT NULL,
LineNumber SMALLINT NOT NULL,
ProductID INT NOT NULL,
ProductQty DECIMAL(18,2) NOT NULL,
PRIMARY KEY(BillNo,LineNumber)
)
--設(shè)置外鍵
ALTER TABLE PP_MPSBody
ADD CONSTRAINT FK_PP_MPSHeader_MPSBody FOREIGN KEY(BillNo) REFERENCES PP_MPSHeader(BillNo)
這是典型的主從表結(jié)構(gòu)。主表記錄什么時(shí)候下達(dá)哪個(gè)單號(hào)的主計(jì)劃,從表記錄的是此計(jì)劃生產(chǎn)哪些產(chǎn)品各多少數(shù)量,通過BillNo進(jìn)行關(guān)聯(lián)。當(dāng)用戶在下達(dá)一份主生產(chǎn)計(jì)劃后,很可能會(huì)發(fā)現(xiàn)由于粗心大意輸錯(cuò)了BillNo中計(jì)劃單號(hào)信息,那么在他修改單號(hào)時(shí),代碼編寫者需要在代碼中控制從表的單號(hào)跟隨主表的單號(hào)進(jìn)行變動(dòng),否則單據(jù)將在外鍵的約束下無法保存,如果沒有外鍵的約束,那么數(shù)據(jù)將失去其完整性。
如果按照上面的3個(gè)注意點(diǎn),解決方案如下(MsSQL):
--主表
CREATE TABLE PP_MPSHeader(
BillId INT PRIMARY KEY,
BillNo VARCHAR(20) NOT NULL,
PlanDate DATETIME NOT NULL
)
--從表
CREATE TABLE PP_MPSBody(
BillId INT PRIMARY KEY,
LineNumber SMALLINT NOT NULL,
ProductID INT NOT NULL,
ProductQty DECIMAL(18,2) NOT NULL,
PRIMARY KEY(BillId,LineNumber)
)
--設(shè)置外鍵
ALTER TABLE PP_MPSBody
ADD CONSTRAINT FK_PP_MPSHeader_MPSBody FOREIGN KEY(BillId) REFERENCES PP_MPSHeader(BillId)
現(xiàn)在,主從表通過BillId進(jìn)行關(guān)聯(lián),當(dāng)產(chǎn)生一份生產(chǎn)計(jì)劃時(shí),生成一個(gè)BillId,對(duì)于用戶來說根本沒有意義,在隨后單據(jù)信息的改動(dòng)中也不會(huì)出現(xiàn)上面的主從信息協(xié)調(diào)問題。同時(shí)從表的信息量小于上面的缺陷設(shè)計(jì)。因?yàn)樵怄IBillNo的長(zhǎng)度從20個(gè)字節(jié)變成了現(xiàn)在的BillId4個(gè)字節(jié),減少了信息的冗余。
這樣的例子其實(shí)很多,比如:
有的設(shè)計(jì)原材料表時(shí),使用零部件圖號(hào)作為主鍵,那就意味著采購、生產(chǎn)、銷售等等相關(guān)表中都會(huì)出現(xiàn)零部件圖號(hào)的外鍵信息,當(dāng)零部件圖號(hào)信息發(fā)生變動(dòng)時(shí),這些所有先關(guān)的信息都需要跟著變動(dòng),這種缺陷如果不從根本上解決,那么你可能需要寫個(gè)零部件圖號(hào)變動(dòng)處理過程,來批量處理這些問題,在處理的過程中可能你還得考慮處理的順序問題……;
有的設(shè)計(jì),使用身份證件號(hào)作為人員表的主鍵,但是身份證后來從15位變成了18位,這就意味著人員表中每個(gè)人的人員身份證信息都需要變動(dòng),如果你是某個(gè)社保機(jī)構(gòu)此應(yīng)用程序的設(shè)計(jì)人員,那么你就需要更新上百萬條記錄;那些所有由人員表通過身份證件號(hào)外聯(lián)出去的信息記錄將會(huì)以億計(jì)數(shù),那么也許余生你就不需要做其他工作了。
所以選擇無意義的鍵值來作為主鍵的一部分,也是從長(zhǎng)遠(yuǎn)意義上來避免類似這種改動(dòng)的發(fā)生。
1.無意義性:此處無意義是從用戶的角度來定義的。這種無意義在一定程度上也會(huì)減少數(shù)據(jù)庫的信息冗余。常常有人稱呼主鍵為內(nèi)部標(biāo)識(shí),為什么會(huì)這樣稱呼,原因之一在于“內(nèi)部”,所謂內(nèi)部從某種程度上來說就是指表記錄,從大的范圍來說就是數(shù)據(jù)庫,如果你在設(shè)計(jì)的時(shí)候選擇了對(duì)用戶來說有意義的信息來作為主鍵,那么遲早會(huì)面對(duì)用戶提出對(duì)這塊信息進(jìn)行更新的需求,那么你就違背了它應(yīng)有的靜態(tài)。
2.靜態(tài)性:主鍵除了唯一地標(biāo)識(shí)一條記錄及外鍵的關(guān)聯(lián)外,應(yīng)不再考慮其他的意義,最理想的狀態(tài)就是在產(chǎn)生后不再變動(dòng),所以在主鍵值產(chǎn)生后應(yīng)考慮不對(duì)他進(jìn)行更新等操作。如果進(jìn)行了更新操作那么至少說明這塊信息對(duì)于用戶來說是有一定的意義,那么你就違背了應(yīng)有的無意義性。(對(duì)數(shù)據(jù)進(jìn)行整合等操作時(shí)可能需要對(duì)主鍵進(jìn)行處理,這樣做是為了保證數(shù)據(jù)庫的完整性——記錄的唯一,不在此考慮范圍之內(nèi)。)
無意義性往往可以決定其靜態(tài)性。
3.簡(jiǎn)短性:既包含主鍵組成字段數(shù)量要少,還包含主鍵中單個(gè)字段存儲(chǔ)類型簡(jiǎn)短,一般采用整形;對(duì)于前者主要考慮的是外鍵關(guān)聯(lián)的因素;對(duì)于后者主要考慮的是性能。主鍵的簡(jiǎn)短對(duì)表的關(guān)聯(lián)便捷性及檢索的性能有極大的幫助。
看看下面具有缺陷的“主生產(chǎn)計(jì)劃表”主鍵設(shè)計(jì)方案(MsSQL):
復(fù)制代碼 代碼如下:
--主表
CREATE TABLE PP_MPSHeader(
BillNo VARCHAR(20) NOT NULL PRIMARY KEY,
PlanDate DATETIME NOT NULL
)
--從表
CREATE TABLE PP_MPSBody(
BillNo VARCHAR(20) NOT NULL,
LineNumber SMALLINT NOT NULL,
ProductID INT NOT NULL,
ProductQty DECIMAL(18,2) NOT NULL,
PRIMARY KEY(BillNo,LineNumber)
)
--設(shè)置外鍵
ALTER TABLE PP_MPSBody
ADD CONSTRAINT FK_PP_MPSHeader_MPSBody FOREIGN KEY(BillNo) REFERENCES PP_MPSHeader(BillNo)
這是典型的主從表結(jié)構(gòu)。主表記錄什么時(shí)候下達(dá)哪個(gè)單號(hào)的主計(jì)劃,從表記錄的是此計(jì)劃生產(chǎn)哪些產(chǎn)品各多少數(shù)量,通過BillNo進(jìn)行關(guān)聯(lián)。當(dāng)用戶在下達(dá)一份主生產(chǎn)計(jì)劃后,很可能會(huì)發(fā)現(xiàn)由于粗心大意輸錯(cuò)了BillNo中計(jì)劃單號(hào)信息,那么在他修改單號(hào)時(shí),代碼編寫者需要在代碼中控制從表的單號(hào)跟隨主表的單號(hào)進(jìn)行變動(dòng),否則單據(jù)將在外鍵的約束下無法保存,如果沒有外鍵的約束,那么數(shù)據(jù)將失去其完整性。
如果按照上面的3個(gè)注意點(diǎn),解決方案如下(MsSQL):
復(fù)制代碼 代碼如下:
--主表
CREATE TABLE PP_MPSHeader(
BillId INT PRIMARY KEY,
BillNo VARCHAR(20) NOT NULL,
PlanDate DATETIME NOT NULL
)
--從表
CREATE TABLE PP_MPSBody(
BillId INT PRIMARY KEY,
LineNumber SMALLINT NOT NULL,
ProductID INT NOT NULL,
ProductQty DECIMAL(18,2) NOT NULL,
PRIMARY KEY(BillId,LineNumber)
)
--設(shè)置外鍵
ALTER TABLE PP_MPSBody
ADD CONSTRAINT FK_PP_MPSHeader_MPSBody FOREIGN KEY(BillId) REFERENCES PP_MPSHeader(BillId)
現(xiàn)在,主從表通過BillId進(jìn)行關(guān)聯(lián),當(dāng)產(chǎn)生一份生產(chǎn)計(jì)劃時(shí),生成一個(gè)BillId,對(duì)于用戶來說根本沒有意義,在隨后單據(jù)信息的改動(dòng)中也不會(huì)出現(xiàn)上面的主從信息協(xié)調(diào)問題。同時(shí)從表的信息量小于上面的缺陷設(shè)計(jì)。因?yàn)樵怄IBillNo的長(zhǎng)度從20個(gè)字節(jié)變成了現(xiàn)在的BillId4個(gè)字節(jié),減少了信息的冗余。
這樣的例子其實(shí)很多,比如:
有的設(shè)計(jì)原材料表時(shí),使用零部件圖號(hào)作為主鍵,那就意味著采購、生產(chǎn)、銷售等等相關(guān)表中都會(huì)出現(xiàn)零部件圖號(hào)的外鍵信息,當(dāng)零部件圖號(hào)信息發(fā)生變動(dòng)時(shí),這些所有先關(guān)的信息都需要跟著變動(dòng),這種缺陷如果不從根本上解決,那么你可能需要寫個(gè)零部件圖號(hào)變動(dòng)處理過程,來批量處理這些問題,在處理的過程中可能你還得考慮處理的順序問題……;
有的設(shè)計(jì),使用身份證件號(hào)作為人員表的主鍵,但是身份證后來從15位變成了18位,這就意味著人員表中每個(gè)人的人員身份證信息都需要變動(dòng),如果你是某個(gè)社保機(jī)構(gòu)此應(yīng)用程序的設(shè)計(jì)人員,那么你就需要更新上百萬條記錄;那些所有由人員表通過身份證件號(hào)外聯(lián)出去的信息記錄將會(huì)以億計(jì)數(shù),那么也許余生你就不需要做其他工作了。
所以選擇無意義的鍵值來作為主鍵的一部分,也是從長(zhǎng)遠(yuǎn)意義上來避免類似這種改動(dòng)的發(fā)生。
您可能感興趣的文章:
- sqlserver主鍵自增的實(shí)現(xiàn)示例
- SQLServer主鍵和唯一約束的區(qū)別
- 如何獲取SqlServer2005表結(jié)構(gòu)(字段,主鍵,外鍵,遞增,描述)
- 深入Mysql,SqlServer,Oracle主鍵自動(dòng)增長(zhǎng)的設(shè)置詳解
- SQLSERVER聚集索引和主鍵(Primary Key)的誤區(qū)認(rèn)識(shí)
- sqlserver數(shù)據(jù)庫主鍵的生成方式小結(jié)(sqlserver,mysql)
- 小議sqlserver數(shù)據(jù)庫主鍵選取策略
- sqlserver設(shè)置主鍵的實(shí)現(xiàn)步驟
相關(guān)文章
SQL?Server開發(fā)智能提示插件SQL?Prompt介紹
這篇文章介紹了SQL?Server開發(fā)智能提示插件SQL?Prompt,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-05-05SQLServer數(shù)據(jù)庫從高版本降級(jí)到低版本實(shí)例詳解
這篇文章主要介紹了SQLServer數(shù)據(jù)庫從高版本降級(jí)到低版本實(shí)例詳解的相關(guān)資料,在工程項(xiàng)目需要遷移的時(shí)候,偶爾會(huì)用到這樣的知識(shí),需要的朋友可以參考下2016-12-12SQL?SERVER常用的日期與時(shí)間查詢總結(jié)
這篇文章介紹了SQL?SERVER常用日期與時(shí)間查詢的方法,文中通過示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-04-04分享SQL Server刪除重復(fù)行的6個(gè)方法
SQL Server刪除重復(fù)行是我們最常見的操作之一,下面就為您介紹六種適合不同情況的SQL Server刪除重復(fù)行的方法,供您參考。2011-09-09SQLServer2016 sa登錄失敗(錯(cuò)誤代碼18456)
18456錯(cuò)誤是因密碼或用戶名錯(cuò)誤而使身份驗(yàn)證失敗并導(dǎo)致連接嘗試被拒或者賬戶被鎖定無法sa登錄,本文就來介紹一下解決方法,感興趣的可以了解一下2023-09-09SQL Server復(fù)制刪除發(fā)布時(shí)遇到錯(cuò)誤18752的問題及解決方法
朋友反饋他無法刪除一臺(tái)SQL Server數(shù)據(jù)庫上的發(fā)布,具體情況為刪除一個(gè)SQL Server Replication的發(fā)布時(shí),遇到這樣的錯(cuò)誤問題如何解決呢,下面小編給大家分享SQL Server復(fù)制刪除發(fā)布時(shí)遇到錯(cuò)誤18752的問題及解決方法,感興趣的朋友一起看看吧2024-01-01