更改外键的引用索引


9

我有这样的事情:

CREATE TABLE T1 (
    Id INT
    ...
    ,Constraint [PK_T1] PRIMARY KEY CLUSTERED [Id]
)

CREATE TABLE T2 (
    ....
    ,T1_Id INT NOT NULL
    ,CONSTRAINT [FK_T2_T1] FOREIGN KEY (T1_Id) REFERENCES T1(Id)
)

出于性能(和死锁)的原因,我在T1上创建了一个新索引

CREATE UNIQUE NONCLUSTERED INDEX IX_T1_Id ON T1 (Id)

但是,如果我检查哪个索引引用了FK,则继续引用聚集索引

select
    ix.index_id,
    ix.name as index_name,
    ix.type_desc as index_type_desc,
    fk.name as fk_name
from sys.indexes ix
    left join sys.foreign_keys fk on
        fk.referenced_object_id = ix.object_id
        and fk.key_index_id = ix.index_id
        and fk.parent_object_id = object_id('T2')
where ix.object_id = object_id('T1');

如果我删除约束并再次创建,它将引用非聚集索引,但这会导致再次检查所有t2 FK。

有没有一种方法可以更改此设置,以便FK_T2_T1使用IX_T1_Id而不是PK_T1而不删除FK并将表锁定在FK检查上?

谢谢!


有一个相关的讨论在这里
i-one

Answers:


6

好吧,继续搜索后,我发现了这篇文章

与普通查询不同,由于更新统计信息,创建新索引甚至重启服务器,它不会选择新索引。我知道将FK绑定到其他索引的唯一方法是删除并重新创建FK,让它自动选择索引,而没有手动控制它的选项。

因此,除非有人可以说,否则我将不得不寻找时间窗口来执行此任务。

谢谢


2

这里阅读MS DOCS之后。

修改外键

若要使用Transact-SQL修改FOREIGN KEY约束,必须首先删除现有的FOREIGN KEY约束,然后使用新定义重新创建它。有关更多信息,请参见删除外键关系和创建外键关系。

如果您相信我,请添加一个新的FK并删除旧的FK。要禁用扫描,您可以使用NO CHECK选项

--DROP TABLE T2
--DROP TABLE T1


CREATE TABLE T1 (
    [Id] INT,
    [NAME] varchar(100), CONSTRAINT [PK_T1] PRIMARY KEY CLUSTERED (id))

CREATE TABLE T2 (
    t2_id int,
    T1_Id INT NOT NULL
    ,CONSTRAINT [FK_T2_T1] FOREIGN KEY (T1_Id) REFERENCES T1(Id)
)


CREATE UNIQUE NONCLUSTERED INDEX IX_T1_Id ON T1 (Id)


select
    ix.index_id,
    ix.name as index_name,
    ix.type_desc as index_type_desc,
    fk.name as fk_name
from sys.indexes ix
    left join sys.foreign_keys fk on
        fk.referenced_object_id = ix.object_id
        and fk.key_index_id = ix.index_id
        and fk.parent_object_id = object_id('T2')
where ix.object_id = object_id('T1');



╔══════════╦════════════╦═════════════════╦══════════╗
 index_id  index_name  index_type_desc  fk_name  
╠══════════╬════════════╬═════════════════╬══════════╣
        1  PK_T1       CLUSTERED        FK_T2_T1 
        2  IX_T1_Id    NONCLUSTERED     NULL     
╚══════════╩════════════╩═════════════════╩══════════╝




 ALTER TABLE T2
    WITH NOCHECK 
    ADD CONSTRAINT [FK_T2_T1_NEW] FOREIGN KEY(T1_Id)
    REFERENCES T1(Id)

select
    ix.index_id,
    ix.name as index_name,
    ix.type_desc as index_type_desc,
    fk.name as fk_name
from sys.indexes ix
    left join sys.foreign_keys fk on
        fk.referenced_object_id = ix.object_id
        and fk.key_index_id = ix.index_id
        and fk.parent_object_id = object_id('T2')
where ix.object_id = object_id('T1');


╔══════════╦════════════╦═════════════════╦══════════════╗
 index_id  index_name  index_type_desc    fk_name    
╠══════════╬════════════╬═════════════════╬══════════════╣
        1  PK_T1       CLUSTERED        FK_T2_T1     
        2  IX_T1_Id    NONCLUSTERED     FK_T2_T1_NEW 
╚══════════╩════════════╩═════════════════╩══════════════╝   

ALTER TABLE T2  
DROP CONSTRAINT FK_T2_T1 

select
    ix.index_id,
    ix.name as index_name,
    ix.type_desc as index_type_desc,
    fk.name as fk_name
from sys.indexes ix
    left join sys.foreign_keys fk on
        fk.referenced_object_id = ix.object_id
        and fk.key_index_id = ix.index_id
        and fk.parent_object_id = object_id('T2')
where ix.object_id = object_id('T1');


╔══════════╦════════════╦═════════════════╦══════════════╗
 index_id  index_name  index_type_desc    fk_name    
╠══════════╬════════════╬═════════════════╬══════════════╣
        1  PK_T1       CLUSTERED        NULL         
        2  IX_T1_Id    NONCLUSTERED     FK_T2_T1_NEW 
╚══════════╩════════════╩═════════════════╩══════════════╝

看看是否可行,我正在尝试再添加一个FK,以便将新的FK链接到创建的新索引,并删除旧的FK。我知道问题不是要删除现有的问题,而是看看此选项是否对您有帮助。

另外,根据Max Vernon的评论:“ WITH NOCHECK选项将防止外键被优化程序信任。在某些时候,您必须更改外键,以便使用ALTER TABLE来信任外键...有检查”

NOCHECK会只在创建的时候被忽略,但执行完整性contraint你在某个时间点运行此。


WITH NOCHECK选项将防止外键被优化器信任。在某些时候,您必须更改外键,以便使用ALTER TABLE ... WITH CHECK
Max Vernon

@MaxVernon,所以这意味着我们别无选择
Biju jose

正确。获得使用新索引的外键的唯一方法是在完整的CHECK选项下重新创建外键。
Max Vernon

@max Vernon,然后将更新答案
Biju jose

感谢@Biju jose提供的正式文件。
马里亚诺·G
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.