Ubah indeks referensi untuk Kunci Asing

9

Saya punya sesuatu seperti ini:

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)
)

Untuk alasan kinerja (dan kebuntuan) saya membuat indeks baru di T1

CREATE UNIQUE NONCLUSTERED INDEX IX_T1_Id ON T1 (Id)

Tetapi jika saya memeriksa Indeks mana yang merujuk pada FK, terus merujuk pada indeks yang dikelompokkan

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');

Jika saya menghilangkan batasan dan membuat lagi itu merujuk pada indeks nonclustered, tetapi ini mengarah untuk memeriksa semua t2 FK lagi.

Apakah ada cara untuk mengubah ini sehingga FK_T2_T1 menggunakan IX_T1_Id bukannya PK_T1 tanpa menjatuhkan FK dan mengunci tabel pada pemeriksaan FK?

Terima kasih!

Mariano G
sumber
Ada diskusi yang relevan di sini .
i-one

Jawaban:

6

Nah, setelah terus mencari saya menemukan artikel ini

Tidak seperti kueri normal, itu tidak akan mengambil indeks baru karena statistik diperbarui, indeks baru dibuat, atau bahkan server sedang reboot. Satu-satunya cara saya sadar untuk memiliki ikatan FK ke indeks yang berbeda adalah dengan menjatuhkan dan membuat ulang FK, membiarkannya secara otomatis memilih indeks tanpa opsi untuk mengontrolnya secara manual.

Karena itu, kecuali seseorang dapat mengatakan sebaliknya, saya harus mencari waktu untuk melakukan tugas ini.

Terima kasih

Mariano G
sumber
2

Setelah membaca MS DOCS di sini .

Untuk memodifikasi kunci asing

Untuk mengubah batasan ASING dengan menggunakan Transact-SQL, Anda harus terlebih dahulu menghapus kendala ASING yang ada dan kemudian buat kembali dengan definisi baru. Untuk informasi lebih lanjut, lihat Menghapus Hubungan Kunci Asing dan Membuat Hubungan Kunci Asing.

Jika Anda, saya percaya menambahkan FK baru dan menghapus yang lama. Untuk menonaktifkan pemindaian, Anda dapat menggunakan NO CHECKopsi

--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 
╚══════════╩════════════╩═════════════════╩══════════════╝

Lihat apakah ini berfungsi, apa yang saya coba adalah menambahkan satu lagi FK sehingga yang baru dikaitkan dengan indeks baru yang dibuat dan lepaskan FK yang lama. Saya tahu pertanyaannya bukan untuk menjatuhkan yang sudah ada tapi lihat apakah opsi ini akan membantu Anda.

Juga, sesuai komentar dari Max Vernon: "opsi WITH NOCHECK akan mencegah kunci asing dipercaya oleh pengoptimal. Pada titik tertentu, Anda harus mengubah kunci asing sehingga dipercaya menggunakan ALTER TABLE ... DENGAN PERIKSA "

The NOCHECKhanya akan diabaikan pada saat penciptaan, tetapi untuk menegakkan contraint integritas Anda telah menjalankan ini di beberapa titik waktu.

Biju jose
sumber
yang WITH NOCHECKpilihan akan mencegah kunci asing yang dipercaya oleh optimizer. Pada titik tertentu, Anda harus mengubah kunci asing agar dapat dipercaya menggunakanALTER TABLE ... WITH CHECK
Max Vernon
@ MaxVernon jadi itu berarti kita tidak punya pilihan
Biju jose
benar. Satu-satunya cara untuk mendapatkan kunci asing untuk menggunakan indeks baru adalah dengan membuat ulang kunci asing dengan opsi PERIKSA utuh.
Max Vernon
@ Max Vernon, akan memperbarui jawabannya kemudian
Biju Jose
Terima kasih @Biju jose untuk dokumen resmi.
Mariano G