Index

唯一索引與“非空”約束相結合是否等同於 PK 約束?

  • March 13, 2020

我有這些舊表定義(來自這裡):

CREATE TABLE [dbo].[JobItems] (
  [ItemId]            UNIQUEIDENTIFIER NOT NULL,
  -- lots of other columns
  CONSTRAINT [PrimaryKey_GUID_HERE] PRIMARY KEY NONCLUSTERED ([ItemId] ASC)
);

CREATE UNIQUE CLUSTERED INDEX [JobItemsIndex]
ON [dbo].[JobItems]([ItemId] ASC);

這有效地產生了兩個相同的索引。我想擺脫其中一個以減少插入時間並釋放磁碟空間。

該表儲存在生產 SQL Azure 數據庫中,因此我無法重建該表,也無法刪除聚集索引(SQL Azure 要求每個表都有一個聚集索引)。

我的要求是保留原始定義提供的所有數據完整性保證,並擺脫非聚集索引。看起來有一個NOT NULL約束和一個唯一索引讓我得到與 PK 約束相同的保證。所以 PK 約束是多餘的,我可以刪除它和基礎索引。

我可以在這裡放棄 PK 約束而不期望有任何破壞嗎?

這有效地產生了兩個相同的索引。

索引不相同。CI 包括所有其他列,而 PK 在葉子上只有 ItemId 鍵列。所以聚集索引可能是非聚集索引大小的 100 倍。

例如,僅使用聚集索引的 COUNT(*) 和分頁查詢將顯著增加成本,因為它們必須使用表掃描。

現在,您的唯一索引和 PK 都唯一標識每一行。這是多餘的。可以刪除索引,並且可以將集群移動到 PK 中。但是,如果 ItemId 上有外鍵,它將失敗。

首先查找外鍵:

Select OBJECT_NAME(constraint_object_id) From sys.foreign_key_columns where referenced_object_id = OBJECT_ID('dbo.JobItems') and COL_NAME(referenced_object_id, referenced_column_id) = 'ItemId'

然後只需刪除它們(索引 + PK)並重新創建一個集群 PK:

If Exists(Select 1 From sys.indexes Where object_id = OBJECT_ID('dbo.JobItems') and name = 'JobItemsIndex')
Begin
   Drop Index [JobItemsIndex] On [dbo].[JobItems]
End
If Exists(Select 1 From sys.indexes Where object_id = OBJECT_ID('dbo.JobItems') and name = 'PrimaryKey_GUID_HERE')
Begin
   Alter Table [dbo].[JobItems] Drop Constraint [PrimaryKey_GUID_HERE]
End

Alter Table [dbo].[JobItems] Add Constraint [PrimaryKey_GUID_HERE] PRIMARY KEY CLUSTERED ([ItemId] ASC)

引用自:https://dba.stackexchange.com/questions/110567