簡體   English   中英

更改其他表中外鍵引用的表的主鍵列

[英]Changing a table's primary key column referenced by foreign key in other tables

在我們的數據庫中(在 SQL Server 2005 上)我們有一個“客戶”表,其主鍵是客戶代碼,代理項,bigint IDENTITY(1,1) 鍵; 該表被我們數據庫中的許多其他表通過外鍵引用。

我們估計的一個新的 CR 實現需要我們將 ID 列類型更改為 varchar,客戶端代碼生成算法從簡單的數字級數轉換為嚴格的 2 字符表示,代碼范圍從 01 到 99,然后進展如下:

1A -> 2A -> ... -> 9A -> 1B -> ... 9Z

我對數據庫設計相當陌生,但我在這里聞到了一些嚴重的問題。 首先,這個客戶端代碼生成算法呢? 如果我需要超出 9Z 代碼限制的 go 的客戶代碼怎么辦?

我有一個問題:這種改變是否可行,表已經填充了相當數量的數據,並被多個實體引用? 如果是這樣,您將如何解決這個問題,以及您將如何實現客戶端代碼生成?

我將保留主鍵,並在生成的客戶端代碼上創建另一個鍵(唯一)。 無論如何我都會這樣做。 使用短數字主鍵而不是長字符鍵總是更好。 在某些情況下,您可能更喜歡 GUID(用於復制目的),但數字 int/bigint 總是更可取。 你可以在這里這里閱讀更多。

我對您提議的最大擔憂是您將被限制為 360 條主要記錄。 這似乎是一個很小的數字。

執行更改是一個多步驟操作。 您需要在核心表及其所有相關表中創建新字段。

要進行就地更新,您需要在核心表中生成代碼。 然后您需要更新所有相關表以具有基於id 的代碼。 然后您需要將外鍵約束添加到所有相關表中。 然后您需要從所有相關表中刪除舊的關鍵字段。

我們只在我們的開發服務器中這樣做了。 當我們升級實時數據庫時,我們為每個數據庫創建了一個新數據庫,並使用查詢舊數據庫並插入新數據庫的 python 腳本復制數據。 我現在為每次軟件升級更新該腳本,以便核心引擎保持不變,但我可以指定不同的表或數據修改。 如果在升級生產時發生意外情況,我可以獲得原始數據庫的完整備份。

支持非身份/指導代碼的一個強有力的論據是,您需要一個人類可讀/可記憶的代碼,並且您需要能夠在兩個系統之間移動記錄。

在 SQL Server 2005 和 2008 中,性能不一定是一個問題。我們最近進行了一次更改,我們從無處不在的 int id 移動到 7 或 8 個字符的“友好”記錄代碼。 我們預計會看到某種性能下降,但實際上我們看到了性能提升

我們還發現我們需要一種快速生成代碼的方法。 我們的代碼有兩部分,一個 3 個字符的字母前綴和一個 4 或 5 位數字的后綴。 一旦我們有大量代碼(15000-20000),我們發現將代碼解析為前綴和后綴並找到最低未使用的代碼會很慢(需要幾秒鍾)。 正因為如此,我們還將前綴和后綴分開存儲(在主鍵表中),以便我們可以快速找到具有特定前綴的下一個可用的最低代碼。 緩存的前綴和后綴使搜索幾乎收費。

我們允許更改代碼,並且它們更改的值通過外鍵關系上的級聯更新規則傳播。 我們在核心代碼表上保留了一個身份密鑰,以簡化代碼的更新。

我們使用 ORM,所以我不知道需要注意哪些具體事項。 在我們最大的實例中,我們也有大約 60,000 個主鍵,但是有數百個相關的表和具有數百萬個與代碼表相關的值的表。

我們獲得的一大優勢是,在許多情況下,我們不需要執行連接即可執行操作。 在軟件的任何地方,用戶都通過友好的代碼引用事物。 我們不必查找 int ID(或連接)來執行某些操作。

新的代碼生成算法不值得考慮。 您可以編寫一個程序,只需幾行代碼即可生成所有可能的代碼。 把它們放在一張桌子上,你就完成了。 您只需要編寫一個 function 即可返回尚未使用的最小的。 這是一個 Ruby 程序,它將為您提供所有可能的代碼。

# test.rb -- generate a peculiar sequence of two-character codes.
i = 1
('A'..'Z').each do |c|
  (1..9).each do |n|
    printf("'%d%s', %d\n", n, c, i)
    i += 1
  end
end

該程序將創建一個 CSV 文件,您應該能夠輕松地將其導入表中。 您需要兩列來控制排序順序。 新值不會自然地按照您的要求指定的方式排序。

我更關心范圍而不是算法。 如果您的要求是正確的,那么您將被限制為 234 個客戶端代碼。 如果你錯了,范圍從“1A”延伸到“ZZ”,你被限制在不到一千。

要在現有表中實現此要求,您需要遵循一個謹慎的過程。 在生產表上嘗試之前,我會在測試環境中嘗試幾次。 (這只是一個草圖。有很多細節。)

  • 創建一個包含兩列的表並將其填充到 map 現有的 bigint 到新的 CHAR(2)。
  • 在所有需要它們的表中創建新的 CHAR(2) 列。
  • 更新所有新的 CHAR(2) 列。
  • 在新的 CHAR(2) 列上創建新的NOT NULL UNIQUEPRIMARY KEY約束和新的FOREIGN KEY約束。
  • 重寫用戶界面代碼 (?) 以定位新列。 (如果您重命名新的 CHAR(2) 和舊的 BIGINT 列,則可能不需要。)
  • 設置目標日期以刪除舊的 BIGINT 列和約束。
  • 等等。

沒有真正解決這是否是一個好主意,但您可以更改外鍵以級聯更新。 完成后會發生什么,當您更新父表中的主鍵時,子表中的相應鍵將相應更新。

暫無
暫無

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

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