外部キーの参照インデックスを変更する


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がPK_T1ではなくIX_T1_Idを使用し、FKを削除してFKチェックでテーブルをロックする方法はありますか?

ありがとう!


ここで関連する議論がありました。
i-one

回答:


6

さて、検索を続けた後、私はこの記事を見つけました

通常のクエリとは異なり、統計が更新されたり、新しいインデックスが作成されたり、サーバーが再起動したりするため、新しいインデックスは取得されません。FKを別のインデックスにバインドすることを知っている唯一の方法は、FKを削除して再作成し、インデックスを自動的に選択して、手動で制御するオプションがないようにすることです。

そこで、誰かが別のことを言うことができない限り、私はこのタスクを実行するための時間枠を探す必要があります。

ありがとう


2

ここで MS DOCSを読んだ後。

外部キーを変更するには

Transact-SQLを使用してFOREIGN KEY制約を変更するには、まず既存のFOREIGN KEY制約を削除してから、新しい定義で再作成する必要があります。詳細については、「外部キー関係の削除」および「外部キー関係の作成」を参照してください。

あなたの場合、私は新しい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 
╚══════════╩════════════╩═════════════════╩══════════════╝

これが機能するかどうかを確認します。私が試みているのは、もう1つFKを追加して、新しいFKを作成された新しいインデックスにリンクし、古いFKを削除することです。問題は既存のものを削除することではないことを知っていますが、このオプションが役立つかどうかを確認してください。

また、Max Vernonからのコメントによると、「WITH NOCHECKオプションは、外部キーがオプティマイザによって信頼されないようにします。ある時点で、ALTER TABLE ...を使用して信頼されるように外部キーを変更する必要があります。チェック付き」

これNOCHECKは作成時にのみ無視されますが、整合性制約を強制するために、ある時点でこれを実行しました。


このWITH NOCHECKオプションは、外部キーがオプティマイザによって信頼されるのを防ぎます。ある時点で、外部キーを使用して信頼できるように変更する必要がありますALTER TABLE ... WITH CHECK
Max Vernon

我々はオプション必要がないことを意味して@MaxVernon
Bijuホセ

正しい。外部キーを取得して新しいインデックスを使用する唯一の方法は、CHECKオプションを変更せずに外部キーを再作成することです。
Max Vernon

@max Vernon、回答を更新します
Biju jose

正式なドキュメントを提供してくれた@Biju joseに感謝します。
マリアーノG
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.