Yabancı Anahtar için başvurulan dizini değiştirme


9

Böyle bir şey var:

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

Performans (ve kilitlenme) nedenleriyle T1'de yeni bir dizin oluşturdum

CREATE UNIQUE NONCLUSTERED INDEX IX_T1_Id ON T1 (Id)

Ancak hangi Endeksin FK'ye başvurduğunu kontrol edersem, kümelenmiş dizine başvurmaya devam eder

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

Kısıtlamayı bırakıp tekrar oluşturursam, kümelenmemiş dizine başvurur, ancak bu, tüm t2 FK'yi tekrar kontrol etmeye yol açar.

FK_T2_T1, FK düşürmeden ve FK kontrolündeki tabloyu kilitlemeden PK_T1 yerine IX_T1_Id kullanacak şekilde bunu değiştirmenin bir yolu var mı?

Teşekkürler!


Burada ilgili bir tartışma vardı .
i-one

Yanıtlar:


6

Peki, aramaya devam ettikten sonra bu makaleyi buldum

Normal bir sorgudan farklı olarak, istatistiklerin güncellenmesi, yeni bir dizin oluşturulması veya hatta bir sunucunun yeniden başlatılması nedeniyle yeni bir dizin almaz. Farklı bir dizine bir FK bağlamanın olduğunun farkında olduğum tek yol, FK'yi bırakmak ve yeniden oluşturmaktır.

Bunun üzerine, eğer birisi aksini söyleyemezse, bu görevi yerine getirmek için bir zaman penceresi aramam gerekecek.

Teşekkürler


2

Burada MS DOCS okuduktan sonra .

Yabancı anahtarı değiştirmek için

Transact-SQL kullanarak bir FOREIGN KEY kısıtlamasını değiştirmek için önce varolan FOREIGN KEY kısıtlamasını silmeli ve sonra yeni tanımla yeniden oluşturmalısınız. Daha fazla bilgi için, bkz. Yabancı Anahtar İlişkilerini Silme ve Yabancı Anahtar İlişkileri Oluşturma.

Senin durumunda yeni bir FK eklemek ve eskisini silmek inanıyorum. Taramayı devre dışı bırakmak için NO CHECKseçeneğini kullanabilirsiniz

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

Bu işe yarayıp yaramadığına bakın, yeni bir tane daha eklemek için yeni bir FK eklemek ve oluşturulan yeni dizine bağlı ve eski FK bırakın. Sorunun mevcut olanı bırakmak değil, bu seçeneğin size yardımcı olup olmayacağını biliyorum.

Ayrıca, Max Vernon'un yorumlarına göre: "WITH NOCHECK seçeneği yabancı anahtarın optimize edici tarafından güvenilmesini önleyecektir. Bir noktada yabancı anahtarı değiştirmeniz gerekir, böylece ALTER TABLE kullanılarak güvenilir olur ... CHECK İLE "

Bu NOCHECKsadece yaratılış sırasında göz ardı edilecektir, ancak bütünlük karşıtlığını zorlamak için bunu belirli bir zamanda yürüttünüz.


WITH NOCHECKyabancı anahtar önleyecektir seçenek optimizer tarafından güvenilir olarak. Bir noktada, yabancı anahtarı değiştirmeniz gerekir, böylece güvenilirALTER TABLE ... WITH CHECK
Max Vernon

@MaxVernon yani bir seçeneğimiz yok
Biju jose

doğru. Yabancı anahtarın yeni dizini kullanmasını sağlamanın tek yolu, yabancı anahtarı CHECK seçeneğiyle sağlam bir şekilde yeniden oluşturmaktır.
Max Vernon

@max Vernon, cevabı güncelleyecek
Biju jose

Resmi bir belge için @Biju jose'ya teşekkürler.
Mariano G
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.