SQL Server มีวิธีเลือกระหว่างดัชนีที่ไม่ซ้ำกันและคีย์หลักหรือไม่
อย่างน้อยก็เป็นไปได้ที่จะสั่งให้ SqlServer อ้างอิงคีย์หลักเมื่อมีการสร้างคีย์แปลกปลอมและมีข้อ จำกัด ของคีย์ทางเลือกหรือดัชนีเฉพาะอยู่บนตารางที่อ้างอิง
หากคีย์หลักต้องถูกอ้างอิงควรระบุเฉพาะชื่อของตารางที่อ้างอิงในนิยามของคีย์ต่างประเทศและรายการของคอลัมน์ที่อ้างอิงควรถูกละเว้น:
ALTER TABLE Child
ADD CONSTRAINT FK_Child_Parent FOREIGN KEY (ParentID)
-- omit key columns of the referenced table
REFERENCES Parent /*(ParentID)*/;
รายละเอียดเพิ่มเติมด้านล่าง
พิจารณาการตั้งค่าต่อไปนี้:
CREATE TABLE T (id int NOT NULL, a int, b int, c uniqueidentifier, filler binary(1000));
CREATE TABLE TRef (tid int NULL);
ที่โต๊ะตั้งใจที่จะตารางอ้างอิงTRef
T
เพื่อสร้างข้อ จำกัด การอ้างอิงหนึ่งสามารถใช้ALTER TABLE
คำสั่งที่มีสองทางเลือก:
ALTER TABLE TRef
ADD CONSTRAINT FK_TRef_T_1 FOREIGN KEY (tid) REFERENCES T (id);
ALTER TABLE TRef
ADD CONSTRAINT FK_TRef_T_2 FOREIGN KEY (tid) REFERENCES T;
โปรดสังเกตว่าในกรณีที่สองไม่มีการระบุคอลัมน์ของตารางที่อ้างอิง ( REFERENCES T
เทียบกับREFERENCES T (id)
)
เนื่องจากยังไม่มีดัชนีคีย์T
การเรียกใช้งานคำสั่งเหล่านี้จะสร้างข้อผิดพลาด
คำสั่งแรกส่งคืนข้อผิดพลาดต่อไปนี้:
เกี่ยวกับ 1776 ระดับ 16 สถานะ 0, บรรทัด 4
ไม่มีคีย์หลักหรือตัวเลือกในตารางอ้างอิง 'T' ที่ตรงกับรายการคอลัมน์อ้างอิงในคีย์ต่างประเทศ 'FK_TRef_T_1'
อย่างไรก็ตามคำสั่งที่สองส่งคืนข้อผิดพลาดที่แตกต่างกัน:
เกี่ยวกับ 1773 ระดับ 16 สถานะ 0, บรรทัด 4
foreign key 'FK_TRef_T_2' มีการอ้างอิงโดยนัยถึง object 'T' ซึ่งไม่มีคีย์หลักที่กำหนดไว้
ดูว่าในการคาดหวังกรณีแรกคือคีย์หลักหรือตัวเลือกในขณะที่ความคาดหวังของเคสที่สองเป็นคีย์หลักเท่านั้น
ตรวจสอบว่า SqlServer จะใช้อย่างอื่นที่ไม่ใช่คีย์หลักด้วยคำสั่งที่สองหรือไม่
หากเราเพิ่มดัชนีเฉพาะและคีย์เฉพาะบนT
:
CREATE UNIQUE INDEX IX_T_1 on T(id) INCLUDE (filler);
CREATE UNIQUE INDEX IX_T_2 on T(id) INCLUDE (c);
CREATE UNIQUE INDEX IX_T_3 ON T(id) INCLUDE (a, b);
ALTER TABLE T
ADD CONSTRAINT UQ_T UNIQUE CLUSTERED (id);
คำสั่งสำหรับFK_TRef_T_1
การสร้างสำเร็จ แต่คำสั่งสำหรับFK_TRef_T_2
การสร้างยังคงล้มเหลวด้วยข่าวสารเกี่ยวกับ 1773
สุดท้ายถ้าเราเพิ่มคีย์หลักในT
:
ALTER TABLE T
ADD CONSTRAINT PK_T PRIMARY KEY NONCLUSTERED (id);
คำสั่งสำหรับFK_TRef_T_2
การสร้างสำเร็จ
ตรวจสอบดัชนีของตารางT
ที่อ้างอิงโดยคีย์ต่างประเทศของตารางTRef
:
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('TRef')
where ix.object_id = object_id('T');
ผลตอบแทนนี้:
index_id index_name index_type_desc fk_name
--------- ----------- ----------------- ------------
1 UQ_T CLUSTERED NULL
2 IX_T_1 NONCLUSTERED FK_TRef_T_1
3 IX_T_2 NONCLUSTERED NULL
4 IX_T_3 NONCLUSTERED NULL
5 PK_T NONCLUSTERED FK_TRef_T_2
เห็นว่าสอดคล้องกับFK_TRef_T_2
PK_T
ดังนั้นใช่กับการใช้งานของREFERENCES T
ต่างประเทศที่สำคัญไวยากรณ์ของถูกแมปไปคีย์หลักของTRef
T
ฉันไม่สามารถค้นหาพฤติกรรมดังกล่าวที่อธิบายไว้ในเอกสารของ SqlServer โดยตรง แต่เฉพาะข่าวสารเกี่ยวกับ 1773 แสดงว่ามันไม่ได้ตั้งใจ การใช้งานดังกล่าวมีความสอดคล้องกับมาตรฐาน SQL ด้านล่างเป็นข้อความที่ตัดตอนมาสั้น ๆ จากมาตรา 11.8 ของ ANSI / ISO 9075-2: 2003
11 คำจำกัดความสคีและการจัดการ
11.8 <ข้อกำหนดการอ้างอิงข้อ จำกัด >
ฟังก์ชัน
ระบุข้อ จำกัด การอ้างอิง
รูปแบบ
<referential constraint definition> ::=
FOREIGN KEY <left paren> <referencing columns> <right paren>
<references specification>
<references specification> ::=
REFERENCES <referenced table and columns>
[ MATCH <match type> ]
[ <referential triggered action> ]
...
กฎไวยากรณ์
...
3) กรณี:
...
b) หาก <ตารางอ้างอิงและคอลัมน์> ไม่ได้ระบุ <รายการคอลัมน์อ้างอิง> ดังนั้นตัวอธิบายตารางของตารางอ้างอิงจะต้องมีข้อ จำกัด เฉพาะที่ระบุคีย์หลัก ให้คอลัมน์อ้างอิงเป็นคอลัมน์หรือคอลัมน์ที่ระบุโดยคอลัมน์ที่ไม่ซ้ำกันในข้อ จำกัด ที่ไม่ซ้ำกันและให้คอลัมน์อ้างอิง
เป็นหนึ่งคอลัมน์ดังกล่าว <ตารางอ้างอิงและคอลัมน์> จะถูกพิจารณาให้ระบุรายการอ้างอิงคอลัมน์โดยนัยที่เหมือนกับรายการคอลัมน์ที่ไม่ซ้ำนั้น
...
Transact-SQL รองรับและขยาย ANSI SQL อย่างไรก็ตามมันไม่สอดคล้องกับ SQL Standard อย่างแน่นอน มีเอกสารชื่อSQL Server Transact-SQL ISO / IEC 9075-2 เอกสารสนับสนุนมาตรฐาน (MS-TSQLISO02 โดยย่อดูที่นี่ ) อธิบายระดับการสนับสนุนที่จัดทำโดย Transact-SQL เอกสารแสดงรายการส่วนขยายและชุดรูปแบบตามมาตรฐาน ตัวอย่างเช่นมันเป็นเอกสารที่MATCH
ข้อไม่ได้รับการสนับสนุนในการกำหนดข้อ จำกัด อ้างอิง แต่ไม่มีรูปแบบเอกสารที่เกี่ยวข้องกับชิ้นส่วนของมาตรฐานที่อ้างถึง ดังนั้นความคิดเห็นของฉันคือพฤติกรรมที่สังเกตได้รับการบันทึกไว้เพียงพอแล้ว
และด้วยการใช้REFERENCES T (<reference column list>)
ไวยากรณ์ดูเหมือนว่า SqlServer จะเลือกดัชนี nonclustered ที่เหมาะสมเป็นอันดับแรกในบรรดาดัชนีของตารางที่ถูกอ้างอิง (อันที่มีค่าน้อยที่สุดindex_id
ดูเหมือนจะไม่ใช่ขนาดที่เล็กที่สุดตามความเห็นของคำถาม) หรือดัชนีกลุ่มถ้ามัน ชุดและไม่มีดัชนี nonclustered ที่เหมาะสม พฤติกรรมดังกล่าวดูเหมือนจะสอดคล้องกันตั้งแต่ SqlServer 2008 (เวอร์ชั่น 10.0) นี่เป็นเพียงการสังเกตแน่นอนไม่มีการรับประกันในกรณีนี้