2010-06-24 34 views
0

我想將使用guid主鍵/聚簇索引的錶轉換爲使用int標識。這是SQL Server 2005中有兩個表MainTableRelatedTable,而目前的表結構如下:如何在轉換爲標識ID時更新guid ID引用

MainTable。[40萬行]

IDGuid - uniqueidentifier - PK 
-- [data columns] 

RelatedTable [400萬行]

RelatedTableID - uniqueidentifier - PK 
MainTableIDGuid - uniqueidentifier [foreign key to MainTable] 
SequenceNumber - int - incrementing number per main table entry since there can be multiple entries related to a given row in the main table. These go from 1,2,3... etc for each MainTableIDGuid value. 
-- [data columns] 

MainTable聚簇索引是當前的主鍵(IDGuid)。 RelatedTable的聚簇索引當前爲(MainTableIDGuid, SequenceNumber)

我想我的轉換是做幾件事情:<

  1. 變化MainTable使用一個整數ID代替GUID
  2. 添加MainTableIDInt列相關的錶鏈接到主表的整數ID
  3. 將主鍵和聚簇索引RelatedTable更改爲(MainTableIDInt, SequenceNumber)
  4. 擺脫guid列。

我寫了一個腳本來做到以下幾點:

  1. 添加IDInt int IDENTITYMainTable。這會執行表重建並生成新的身份標識值。
  2. MainTableIDInt int列添加到RelatedTable

下一步是與其相應MainTable.IDInt值[基於的GUID ID的匹配]來填充每一行的列RelatedTable.MainTableIDInt。這是我掛上的一步。我知道這不會很快,但我希望能儘可能地發揮它的作用。

我可以寫一個SQL語句,這是否更新:

UPDATE RelatedTable 
SET RelatedTable.MainTableIDInt = (SELECT MainTable.IDInt FROM MainTable WHERE MainTable.IDGuid = RelatedTable.MainTableIDGuid) 

UPDATE RelatedTable 
SET RelatedTable.MainTableIDInt = MainTable.IDInt 
FROM RelatedTable 
LEFT OUTER JOIN MainTable ON RelatedTable.MainTableIDGuid = MainTable.IDGuid 

的「顯示估計的執行計劃」顯示大致相同的這兩個查詢。它吐出的執行計劃執行以下操作:

  1. 簇索引掃描過MainTableRelatedTable和確實一個合併加入他們[估計行數的= 400百萬]
  2. 排序[估計行數的= 400百萬]在RelatedTable [估計的行數= 400億]

我關心的這個性能

  • 聚集索引更新[排序4個億行聽起來不愉快。我擔心這些執行計劃的執行是否合理?有沒有更好的方法來更新我的相關表的新ID,它將根據表的大小進行縮放?

  • +0

    如果您發佈的是代碼或XML,請**在文本編輯器中突出顯示這些行,然後單擊編輯器工具欄上的「代碼」按鈕(101 010)以精確地格式化和語法突出顯示它!此外,如果您使用1.,2等枚舉 - 在每一行結尾處確實不需要
    。如果要突出顯示固定字體和灰色背景中的標識符(如表格名稱),請標記標識符並按Ctrl-K進行格式化。 – 2010-06-24 05:24:59

    +0

    這次更新*會*嚴重地對您的系統徵稅,但我沒有看到任何「魔法子彈」如何使這個消失。你需要更新所有4億行 - 真的沒有辦法。唯一的問題是你是否可以在你的第二次更新聲明中使用INNER JOIN - 但是這可能不會產生太大的影響, – 2010-06-24 05:26:46

    回答

    1

    首先,這將是一個令人頭疼的問題。其次,在我掌握數據之前,我不會更改任何索引或約束條件。也就是說,我會添加標識列,但不能使其成爲主鍵或聚集索引。然後,我會將即將成爲新的外鍵添加到各個表中。您的查詢應該是這樣的:

    Update ChildTable 
    Set NewIntForeignKeyId = P.NewIntPrimaryKey 
    From ChildTable As C 
        Join ParentTable As P 
         On P.PrimaryKey = C.ForeignKey 
    

    首先,請注意,我使用的是內部聯接。對於這種類型的查詢,沒有理由使用外部聯接,因爲您最終將在新列之間實施參照完整性。其次,如果先填充列,然後重新生成約束,則會更快,因爲您可以利用現有索引。請記住,當您更改聚簇索引時,它會重建所有非聚簇索引。如果桌子很大,那將是一個嚴重的問題。一旦你有了這些數據,我就會放棄所有主要約束,唯一約束,外鍵約束和唯一索引。最後放置聚集索引/約束。然後,我會將聚簇索引添加到所有表中,然後重新創建唯一約束,外鍵約束和索引。如果在重新創建聚集索引之前不刪除現有索引,它將重建兩次現有索引:一次刪除聚集索引,一次重新創建聚簇索引。

    順便說一句,我非常懷疑有一種方法可以避免這種事情的表掃描,因爲你要更新每一行。