เปลี่ยนดัชนีอ้างอิงสำหรับ Foreign Key


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 ใช้ IX_T1_Id แทน PK_T1 โดยไม่ต้องวาง FK และล็อคตารางในการตรวจสอบ FK หรือไม่

ขอบคุณ!


มีการอภิปรายที่เกี่ยวข้องเป็นที่นี่
ฉันหนึ่ง

คำตอบ:


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

ดูว่ามันใช้งานได้หรือไม่สิ่งที่ฉันพยายามคือการเพิ่ม FK อีกหนึ่งรายการใหม่เพื่อเชื่อมโยงกับดัชนีใหม่ที่สร้างขึ้นและปล่อย FK เก่า ฉันรู้ว่าคำถามนี้ไม่ได้เป็นการทิ้งคำถามที่มีอยู่ แต่ดูว่าตัวเลือกนี้จะช่วยคุณได้หรือไม่

นอกจากนี้ตามความคิดเห็นจาก Max Vernon: "ตัวเลือก WITH NOCHECK จะป้องกันไม่ให้ foreign key เชื่อถือได้โดย optimizer ในบางจุดคุณจะต้องเปลี่ยน foreign key เพื่อให้เชื่อถือได้โดยใช้ ALTER TABLE ... ด้วยการตรวจสอบ "

NOCHECKจะถูกละเว้นเฉพาะในช่วงเวลาของการสร้าง แต่การบังคับใช้ contraint สมบูรณ์ที่คุณได้ทำนี้ในบางจุดของเวลา


WITH NOCHECKตัวเลือกที่จะป้องกันไม่ให้ต่างประเทศที่สำคัญได้รับการไว้วางใจจากการเพิ่มประสิทธิภาพ ในบางจุดคุณจะต้องเปลี่ยนรหัสต่างประเทศเพื่อให้เชื่อถือได้โดยใช้ALTER TABLE ... WITH CHECK
Max Vernon

@ MaxVernon นั่นหมายความว่าเราไม่มีตัวเลือก
Biju jose

แก้ไข. วิธีเดียวที่จะได้รับ foreign key เพื่อใช้ดัชนีใหม่คือการสร้าง foreign key ขึ้นมาใหม่โดยที่ตัวเลือก CHECK ยังคงเหมือนเดิม
Max Vernon

@max Vernon จะอัปเดตคำตอบแล้ว
Biju jose

ขอบคุณ @Biju jose สำหรับเอกสารที่เป็นทางการ
Mariano G
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.