Modifica indice di riferimento per una chiave esterna


9

Ho qualcosa del genere:

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

Per motivi di prestazioni (e deadlock) ho creato un nuovo indice su T1

CREATE UNIQUE NONCLUSTERED INDEX IX_T1_Id ON T1 (Id)

Ma se controllo a quale indice fa riferimento l'FK, continuo a fare riferimento all'indice cluster

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

Se lascio cadere il vincolo e lo creo di nuovo, fa riferimento all'indice non cluster, ma questo porta a controllare di nuovo tutto l'FK t2.

C'è un modo per cambiare questo in modo che FK_T2_T1 usi IX_T1_Id invece di PK_T1 senza far cadere l'FK e bloccare la tabella sul controllo FK?

Grazie!


C'è stata una discussione pertinente qui .
i-one,

Risposte:


6

Bene, dopo aver continuato la ricerca ho trovato questo articolo

A differenza di una normale query, non raccoglierà un nuovo indice a causa dell'aggiornamento delle statistiche, della creazione di un nuovo indice o persino del riavvio di un server. L'unico modo in cui sono a conoscenza di avere un binding FK con un indice diverso è di eliminare e ricreare l'FK, consentendogli di selezionare automaticamente l'indice senza opzioni per controllarlo manualmente.

Pertanto, a meno che qualcuno non possa dire diversamente, dovrò cercare una finestra temporale per eseguire questo compito.

Grazie


2

Dopo aver letto MS DOCS qui .

Per modificare una chiave esterna

Per modificare un vincolo FOREIGN KEY utilizzando Transact-SQL, è necessario prima eliminare il vincolo FOREIGN KEY esistente e quindi ricrearlo con la nuova definizione. Per ulteriori informazioni, vedere Elimina relazioni con chiave esterna e Crea relazioni con chiave esterna.

Nel tuo caso credo di aggiungere un nuovo FK ed eliminare quello vecchio. Per disabilitare la scansione puoi usare l' NO CHECKopzione

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

Vedi se funziona, quello che sto provando è di aggiungere un altro FK in modo che quello nuovo sia collegato al nuovo indice creato e rilasci il vecchio FK. So che la domanda non è abbandonare quella esistente ma vedere se questa opzione ti aiuterà.

Inoltre, secondo i commenti di Max Vernon: "l'opzione WITH NOCHECK eviterà che la chiave esterna venga considerata attendibile dall'ottimizzatore. Ad un certo punto, dovresti modificare la chiave esterna in modo che sia attendibile utilizzando ALTER TABLE ... CON CONTROLLO "

Il NOCHECKsarà ignorato solo al momento della creazione, ma di far rispettare l'integrità contraint si è eseguito questo ad un certo punto del tempo.


l' WITH NOCHECKopzione eviterà che la chiave esterna venga considerata attendibile dall'ottimizzatore. Ad un certo punto, dovresti modificare la chiave esterna in modo che sia affidabile usandoALTER TABLE ... WITH CHECK
Max Vernon,

@MaxVernon quindi questo significa che non abbiamo un'opzione
Biju jose

corretta. L'unico modo per ottenere la chiave esterna per utilizzare il nuovo indice è ricreare la chiave esterna con l'opzione CHECK intatta.
Max Vernon,

@max Vernon, aggiornerà la risposta allora
Biju jose

Grazie @Biju jose per un documento ufficiale.
Mariano G,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.