簡體   English   中英

我該如何處理這個泛化設計問題?

[英]How can I handle this generalization design issue?

在我們的數據庫 model 中,我們有一個受益人實體。 受益人可以是自然人公司受益人; 物理受益人具有許多屬性,例如姓名、姓氏、性別等; 此外,受益人(法人或自然人)可以是外國人,也可以不是; 這種進一步的區別轉化為一組“通用”屬性的不同域值(例如,在我居住的意大利,稅號可能與英國的稅號具有不同的數據格式)。

我們現在正在重新設計我們的受益人表,因為最初從事數據庫分析和建模的開發人員做了一個(IMO)短視的選擇。 他將主鍵約束放在屬性 BeneficiaryName 上,該屬性已用於存儲公司名稱(例如“Microsoft Corporation”)以用於公司受益人或姓氏(例如 Smith)用於實際受益人。 這樣,我們就有了(不可接受的)約束,即我們的數據庫中不能有超過 1 個姓“Smith”(或名為“Smith”的公司)的受益人。

我對這種“重構”的方法將引入對受益人實體的概括; 我會

  1. 清理受益人表,只保留常用數據;
  2. 在 Beneficiary 表中添加一個代理主鍵,我們稱之為 BeneficiaryID;
  3. 拆分受益人表,創建兩個子實體( CorporateBeneficiaryPhysicalBeneficiary ,由主受益人表中的標志區分),與受益人表有 1..1 關聯(外鍵將引用 BeneficiaryID)
  4. 查找CorporateBeneficiaryPhysicalBeneficiary的(重要)主鍵;

這應該解決前面提到的 BeneficiaryName 唯一性問題。 到目前為止似乎還可以?

我遇到的真正問題是:我如何/應該如何處理這個 model 中“外來”屬性添加的進一步復雜性? 我是否應該按原樣保留外國,即受益人中的標志屬性? 如果是這樣,我如何在不重復屬性(zipcode_foreign、zipcode、taxid_foreign、taxid 等)的情況下處理概念上相似的信息(即郵政編碼、稅號)對不同屬性的需求? 我真的應該努力將不同的域值容納到一個字段中嗎?

任何建議都會受到歡迎...

“清理受益人表,只保留常用數據;”

正是有什么事情要做。

“在 Beneficiary 表中添加一個代理主鍵,我們稱之為 BeneficiaryID;”

可能有用,但不要忘記如果存在“自然”標識符,那么它的唯一性也應該被強制執行。

“拆分受益人表,創建兩個子實體(CorporateBeneficiary & PhysicalBeneficiary”

是的。 觀察到很難強制執行“絕對”數據完整性(同時強制所有自然受益人都是受益人,所有非自然受益人也是受益人,並且所有受益人要么是自然受益人要么是非自然受益人)。

“被主受益人表中的標志區分”

沒有。 不會那樣做。 該標志是冗余的,冗余增加了復雜性而不增加價值。 如果您想知道受益人是自然人還是非自然人,請查看記錄該事實的表格。

“為 CorporateBeneficiary 和 PhysicalBeneficiary 查找(重要的)主鍵;”

如果您一般為 Benficiaries 引入代理項,則無需在這些其他表中復制自然標識符。 這又是一種冗余,增加了復雜性而不增加價值。

“我遇到的真正問題是:我如何/應該如何處理這個 model 中的“外來”屬性添加的進一步復雜性?”

可以應用相同的方法,區分 National 和 ExtraNational(對於公司和實體受益人),如果數據完整性在涉及到(例如,至少是 National Benficiaries)時至關重要,那么這可能是從建議到絕對需要的任何方法。 例如,法律可能會強制您根據國家規則驗證國家 SSN 號碼或國家公司識別號碼是否“有效”。 如果此類法規適用,那么這些規則由 DBMS 簽入和由DBMS 簽入可能至關重要,而不僅僅是您的應用程序。 當然,對於非國民來說,通常也不需要進行類似的檢查,甚至一般來說也不可能。

如果您在數據庫結構中考慮到 National 和 Non-National 之間的這種區別,您很可能還希望創建一個將兩者(National 和 Non-National)“聯合”在一起的視圖,然后您將不得不將您的數據“轉換”為“統一”“通用”格式,這可能只是 CHAR(即使您知道,例如,對於 National PhysicalBeneficiaries,內容將是他們的 SSN 號碼,您知道該號碼由一些固定號碼組成位數)。

如果您不必在數據庫結構中考慮國家和非國家之間的這種區別,那么您將被迫在將保存數據的單個表中使用相同的“統一”“通用”格式對於國內和國外。

在一個字段中容納不同的域值將復制您現在在主要受益人表中遇到的問題類型 - 在將來的某個時候。 我會采用這種方法:

修改 CorporateBeneficiary/PhysicalBeneficiary 表中的建議鍵,如下所示:

  1. 按照您的建議添加代理主鍵(BeneficiaryID)
  2. 使用適當的數據庫或站點機制將 BeneficiaryID 生成為唯一的生成值。
  3. 使 CorporateBeneficiary (CB) 和 PhysicalBenificiary (PB) 的主鍵相同 - 即 BeneficiaryID。
  4. 將 CB 和 PB 的主鍵設為引用 Beneficiary 表的外鍵。

那么對於國外的細節采取類似的做法:

  1. 為每個國家添加一個包含公共列的表,但引用適當的域。
  2. 以與 CB/PB 類似的方式設置新表 - 即作為與受益人表的關系。

然后基於左連接創建視圖以創建“虛擬表” - Beneficiary/PB/Foreign 詳細信息。 這些視圖將成為獲取信息的基礎。

如果您有非常大的數據集(> 10^7 行),您可能會發現我對驗證郵政編碼問題的回答很有趣。 這是一個很長的回應; 不簡單; 並且是巨大的矯枉過正,除非體積非常大。

編輯

如果您的數據量較低,@James Anderson 建議的多行(例如地址)行將非常合適。

你的想法是正確的。

我建議您有一個單獨的“地址”表供所有受益人共享。 (您實際上是在描述對人和公司相同的郵件投遞。),但是這里處理 i18n 問題的最簡單方法是保持簡單的 Line1、Line2、Line3。 第 4 行和國家代碼。

我什至不會 go 有一個特定的郵政編碼,因為這些郵政編碼從簡單的 4 位數字到英國 /[A-Z0-9]{2,4} [A-Z0-9]{2,4 }/ 甚至是愛爾蘭共和國,沒有任何郵政編碼(官方推理“哦,我們不需要那樣的東西,我們知道你住在哪里。”)。 此外,郵政編碼的常規 position 因國家/地區而異(UK 在其末尾單獨一行,CH 在城市名稱之前等),一些域跟隨城市,縣,state 模式其他地方沒有有州或縣或不在郵件地址中使用它們。

為了概括,您可以通過三個概念為數據庫設計它們:

(解釋 1 個泛化,2 個子類型)


1. 一張桌子供所有人使用

在這里,您在一張表中擁有來自泛化和子類型的所有屬性。

優點:

  • 不需要 JOIN,不需要 UNION(=因此它通常是最快的可能性)
  • 輕松快速地從整個人群中獲取東西
  • 輕松快速地擺脫泛化屬性
  • 輕松快速地從子類型屬性中獲取內容

缺點:

  • 具有具有新屬性的新子類型時重新設計表
  • 未使用屬性的許多NULL 值
  • 用於標記特定記錄是什么子類型的附加屬性
  • (它看起來像丑陋的設計,但通常它是如此令人難以置信的快得多......)

PK/FK:一個 PK,沒有 FK

對於您的示例:“受益人”只有一張表。


2.兩張桌子

只有子類型的表。 沒有表格可以概括。

優點:

  • 非常容易和快速地訪問一個特定子類型的全部數據
  • 易於為特定子類型添加新屬性

缺點:

  • 很難從整個人口中得到東西(UNION = 慢)
  • 難以為泛化添加新屬性(必須更改所有表)

PK/FK:每張桌子都有自己的 PK,沒有 FK

對於您的示例:“CorporateBeneficiary”和“PhysicalBeneficiary”的兩個表


3. 三張桌子

有一個自己的表用於概括和每個子類型。 (這是你選擇的。)

優點:

  • 輕松訪問泛化屬性
  • 輕松訪問子類型屬性
  • 易於添加新屬性

缺點:

  • 獲取整個實體的所有屬性很昂貴(JOIN = 慢)

PKs/FKs:理想情況下,所有桌子都使用一個 PK 序列。 (即 Oracle 序列) 在子類型表中,pk 列同時是泛化表的 fk 列。 這在 DBMS 中可能有點復雜,因為您沒有 Oracle 序列之類的東西。 可能需要在子類型中具有單獨的 pk 和 fk 列,並為每個表提供自己的 PK 序列。 (即因為序列 gen 是一個列屬性)


您選擇哪一種取決於您的要求。 1.) 和 3.) 您會經常看到 2.) 的情況非常罕見,而且許多開發人員不知道這種設計。

就個人而言,當我沒有其他邊界條件時,我選擇 3,因為我發現這是最干凈的解決方案。 但由於性能原因,我過去也選擇了選項 1。 不記得我從大學開始就做過類似選項 2 的事情。 :p

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM