2008-11-20 72 views
0

我有一個相當大的數據庫與一個主表的GUID(自定義GUID像算法)主鍵和8個子表與外鍵關係GUID列。所有的表格都有大約3-8百萬條記錄。這些表中沒有任何BLOB/CLOB/TEXT或任何其他花哨的數據類型,只有正常的數字,變量,日期和時間戳(每個表中大約15-45列)。除主鍵和外鍵之外,沒有分區或其他索引。更新大表的主表和子表的主鍵

現在,自定義GUID算法已更改,雖然沒有衝突,但我想遷移所有舊數據以使用使用新算法生成的GUID。沒有其他列需要更改。首要任務是數據完整性,性能是次要的。

一些我能想到的可能的解決方案的人(因爲你可能會發現它們都圍繞着只有一個想法)

  1. 添加新列ngu_id和新gu_id填充;禁用約束;用ngu_id作爲gu_id更新子表; renaname ngu_id-> gu_id;重新啓用約束條件
  2. 從子表讀取一條主記錄及其相關的子記錄;用新的gu_id插入到同一個表中;使用舊gu_id刪除所有記錄
  3. 下降約束;向主表添加觸發器,以便更新所有子表;用新的gu_ids開始更新舊的gu_id;重新啓用約束
  4. 向主表添加觸發器,以便更新所有子表;用新的新gu_id開始更新舊的gu_id
  5. 在所有主表和子表上創建新的列ngu_ids;在ngu_id列上創建外鍵約束;將更新觸發器添加到主表以將值級聯到子表;將新的gu_id值插入ngu_id列;基於gu_id刪除舊的外鍵約束;刪除gu_id列並將ngu_id重命名爲gu_id;必要時重新創建約束;
  6. 使用on update cascade如果有的話?

我的問題是:

  1. 有沒有更好的辦法? (不能把我的頭埋在沙裏,得這麼做)
  2. 什麼是最合適的方法來做到這一點? (我必須在oracle,sqlserver和mysql4中執行此操作,因此歡迎使用特定的供應商)
  3. 這種練習的典型失敗點以及如何最小化它們?

如果你是我到目前爲止,謝謝你,希望你能幫助:)

回答

2

你的想法應該工作。第一個可能是我會使用的方式。在做這件事時需要注意一些事項和事情: 除非您有當前的備份,否則不要這樣做。 我會將兩個值留在主表中。這樣,如果你必須從一些舊文件中找出你需要訪問的記錄,那麼你可以這樣做。 將數據庫關閉以進行維護,同時執行此操作並將其置於單用戶模式。在做這樣的事情時,你需要的最後一件事是用戶試圖在中途進行更改。當然,單用戶模式下的第一個動作就是上面提到的備份。當使用量最輕時,您可能應該安排停機時間一段時間。 首先在dev上進行測試!這也應該給你一個關於你需要多長時間關閉生產的背景。你也可以嘗試幾種方法來看哪個是最快的。 請務必提前告知用戶數​​據庫將在預定時間進行維護以及何時可以再次使用。確保時機正常。當他們計劃遲到以運行季度報告並且數據庫不可用並且他們不知道時,它真的讓人很生氣。 有相當多的記錄,您可能希望批量運行子表的更新(原因不是使用級聯更新)。這可能比試圖用一次更新更新500萬條記錄要快。但是不要試圖一次更新一條記錄,否則你明年仍然會在這裏完成這項任務。 刪除所有表中GUID字段的索引並在完成後重新創建。這應該會改善變更的效果。

0

創建一個新的表格,其中包含舊的和新的pk值。在兩列上放置唯一的約束,以確保您迄今尚未破壞任何內容。

禁用約束。

針對所有表運行更新以將舊值修改爲新值。

啓用PK,然後啓用FK。

0

很難說什麼是「最好」或「最合適」的方法,因爲您沒有描述您在解決方案中尋找什麼。例如,在遷移到新ID時,是否需要查詢表格以進行查詢?他們是否需要同時修改?儘可能快地完成遷移很重要嗎?減少用於遷移的空間是否很重要?儘管如此,如果他們都滿足您的要求,我寧願選擇其他想法的第一名。

任何涉及更新子表的觸發器似乎都很容易出錯並且過於複雜,並且可能無法像#1那樣執行。

假設新ID永遠不會與舊ID衝突是否安全?如果不是,那麼一次一個地更新ID的解決方案將不得不擔心碰撞 - 這會很匆忙。

您是否考慮過使用CREATE TABLE AS SELECT(CTAS)使用新ID填充新表?您將製作現有表格的副本,這將需要額外的空間,但是它可能比現有表格更新更快。這個想法是:(i)使用CTAS創建新的ID代替舊的ID,(ii)在新的表上適當地創建索引和約束,(iii)刪除舊的表,(iv)將新的表格以舊名稱。

0

實際上,它取決於你的RDBMS。

使用Oracle,最簡單的選擇是使所有外鍵約束「延遲」(檢查提交),在單個事務中執行更新,然後提交。