Зміна посилального індексу для зовнішнього ключа


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)

Але якщо я перевіряю, на який Index посилається 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');

Якщо я скидаю обмеження і створюю його знову, він посилається на некластеризований індекс, але це призводить до того, щоб знову перевірити всі FK2.

Чи є спосіб змінити це, щоб FK_T2_T1 використовував IX_T1_Id замість PK_T1, не скидаючи FK і не замикаючи таблицю на перевірку FK?

Дякую!


Було відповідне обговорення тут .
i-one

Відповіді:


6

Ну а після продовження пошуку я знайшов цю статтю

На відміну від звичайного запиту, він не вибере новий індекс через оновлення статистики, створення нового індексу або навіть перезавантаження сервера. Єдиний спосіб, коли я знаю про те, щоб FK прив'язувався до іншого індексу, - це скинути і відтворити FK, дозволяючи йому автоматично вибирати індекс без будь-яких варіантів керування ним вручну.

Після цього, якщо хтось не може сказати інше, мені доведеться шукати вікно часу для виконання цього завдання.

Дякую


2

Після прочитання MS DOCS тут .

Щоб змінити іноземний ключ

Щоб змінити обмеження FOREIGN KEY за допомогою Transact-SQL, потрібно спочатку видалити існуюче обмеження 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 
╚══════════╩════════════╩═════════════════╩══════════════╝

Подивіться, чи це працює, я намагаюся додати ще один ФК, щоб новий був пов’язаний з новим створеним індексом та скинув старий ФК. Я знаю, що питання не впадати з існуючого, але подивитися, чи допоможе вам цей варіант.

Крім того, згідно з коментарями Макса Вернона: "Параметр" NO NO "перевіряє оптимізатор довіри іноземному ключу. У якийсь момент вам доведеться змінити іноземний ключ, щоб він довірявся, використовуючи ALTER TABLE ... З ПЕРЕВІРОМ "

Захист NOCHECKбуде ігноруватися лише під час створення, але щоб застосувати контракт про цілісність, ви запустили це в якийсь момент часу.


WITH NOCHECKваріант дозволить запобігти зовнішній ключ довіряють оптимізатором. У якийсь момент вам доведеться змінити зовнішній ключ, щоб він довіряв, використовуючиALTER TABLE ... WITH CHECK
Макс Вернон,

@MaxVernon, це означає, що у нас немає варіанту
Biju jose

правильно. Єдиний спосіб отримати зовнішній ключ для використання нового індексу - це відтворити зовнішній ключ з опцією CHECK неушкодженою.
Макс Вернон

@max Вернон, оновить відповідь потім
Biju jose

Дякую @Biju jose за офіційний документ.
Маріано Г
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.